Pour mieux comprendre ce qu'il se passe, nous activons le débogage.
Voici un URL que j'ai mise en place pour rediriger de manière permanent vers mon fil Atom à l'adresse http://diveintomark.org/xml/atom.xml.
Evidemment, lorsque nous essayons de télécharger les données à cette adresse, le serveur renvoi un code de statut 301, signalant que la ressource a été déplacée de manière permanente.
Le serveur renvoi également un en-tête Location: avec la nouvelle adresse de ces données.
urllib2 remarque le code de redirection et tente automatiquement d'obtenir les données à la nouvelle adresse spécifiée dans l'en-tête
Location:.
L'objet obtenu de opener contient la nouvelle adresse permanente et tous les en-têtes retourné à la seconde requête (faite sur la nouvelle adresse
permanente). Mais le code de statut manque, nous n'avons donc aucun moyen de savoir par la programmation si cette redirection
est temporaire ou permanente. Or, cette information est très importante. Si c'est une redirection temporaire, nous devons
continuer de demander les données à l'ancienne adresse. Si c'est une redirection permanente, nous devons désormais demander
les données à la nouvelle adresse.
C'est loin d'être parfait, mais c'est facile à corriger. urllib2 ne se comporte pas exactement comme nous le souhaitons dans la gestion des codes 301 et 302, nous allons donc redéfinir ce comportement. Comment ? Avec un gestionnaire d'URL spécialisé, comme nous l'avons fait pour prendre en charge les codes 304.
Exemple 11.11. Definition du gestionnaire de redirection
Cette classe est définie dans openanything.py.
class SmartRedirectHandler(urllib2.HTTPRedirectHandler): def http_error_301(self, req, fp, code, msg, headers):
result = urllib2.HTTPRedirectHandler.http_error_301(
self, req, fp, code, msg, headers)
result.status = code return result
def http_error_302(self, req, fp, code, msg, headers):
result = urllib2.HTTPRedirectHandler.http_error_302(
self, req, fp, code, msg, headers)
result.status = code
return result
La gestion des redirections est définie dans urllib2 dans une classe appelée HTTPRedirectHandler. Nous ne voulons pas redéfinir entièrement son comportement, nous voulons simplement l'étendre un peu, nous dérivons donc
HTTPRedirectHandler de manière à pouvoir appeler la classe ancêtre pour faire le gros du travail.
Quand il reçoit un code de statut 301 du serveur, urllib2 recherche parmi ses gestionnaires et appelle la méthode http_error_301. La première chose que la notre fait est d'appeler la méthode http_error_301 de la classe ancêtre, qui s'occupe du travail de base consistant à chercher l'en-tête Location: et à suivre la redirection à la nouvelle adresse.
Voici l'étape-clé : avant le retour de fonction, nous stockons le code de statut (301) pour que le programme appelant puisse y accéder plus tard.
Les redirections temporaires (codes de statut 302) fonctionnent de la même manière : réécriture de la méthode http_error_302, appel de l'ancêtre et sauvegarde du code de statut avant retour.
A quoi cela nous avance-t-il ? Nous pouvons maintenant construire un opener d'URL avec notre gestionnaire de redirection spécialisé et il suivra toujours les redirections automatiquement, mais maintenant
il exposera également le code de statut de redirection.
Exemple 11.12. Utilisation du gestionnaire de redirection pour détecter les redirections permanentes
D'abord, nous construisons un opener d'URL avec le gestionnaire de redirection que nous venons de définir.
Nous avons envoyé une requête et nous avons reçu un code de statut 301 en réponse. A ce moment, la méthode http_error_301 est appelée. Nous appelons la méthode ancêtre qui suit la redirection et envoi une requête à la nouvelle adresse (http://diveintomark.org/xml/atom.xml).
Voici le bénéfice de notre travail : maintenant, nous n'avons pas seulement accès à la nouvelle URL, mais également au code
de statut de redirection, nous pouvons donc voir qu'il s'agit d'une redirection permanente. La prochaine fois que nous demanderont
ces données, nous devrons les demander à la nouvelle adresse (http://diveintomark.org/xml/atom.xml, comme spécifié dans f.url). Si nous avons stocké l'adresse dans un fichier de configuration ou une base de données, nous devons la mettre à jour pour
ne pas continuer à envoyer des requêtes à l'ancienne adresse. Il faut mettre à jour notre carnet d'adresse.
Le gestionnaire de redirection peut aussi nous apprendre quand nous ne devons pas mettre à jour notre carnet d'adresse.
Exemple 11.13. Utilisation du gestionnaire de redirection pour détecter les redirections temporaires.
C'est une URL d'exemple que j'ai configurée pour signaler aux clients de se rediriger temporairement sur http://diveintomark.org/xml/atom.xml.
Le serveur renvoi un code de statut 302, ce qui indique une redirection temporaire. Le nouvel emplacement temporaire des données est donné dans l'en-tête Location:.
urllib2 appelle notre méthode http_error_302, qui appelle la méthode ancêtre du même nom dans urllib2.HTTPRedirectHandler, qui suit la redirection vers le nouvel emplacement. Puis notre méthode http_error_302 stocke le code de statut (302) pour que l'application appelante puisse l'utiliser plus tard.
Nous y voilà, après avoir suivi la redirection vers http://diveintomark.org/xml/atom.xml. f.status nous dit que c'était une redirection temporaire, ce qui signifie que nous devons continuer à chercher les données à l'adresse
originelle (http://diveintomark.org/redir/example302.xml). Peut-être que nous serons redirigés encore la prochaine fois, mais peut-être que non. Peut-être que nous seront redirigés
vers une adresse différente, nous ne pouvons pas le dire. Le serveur nous a indiqué que cette redirection était temporaire,
nous devons suivre cette indication et maintenant que nous exposons assez d'information pour le faire, l'application appelante
peut suivre cette indication.