Nous avons vu toutes les pièces nécessaires à la construction d'un client de services Web intelligent. Maintenat, voyons comment
tout cela s'assemble.
Exemple 11.17. La fonction openanything
Cette fonction est définie dans openanything.py.
def openAnything(source, etag=None, lastmodified=None, agent=USER_AGENT):
# non-HTTP code omitted for brevityif urlparse.urlparse(source)[0] == 'http': # open URL with urllib2
request = urllib2.Request(source)
request.add_header('User-Agent', agent) if etag:
request.add_header('If-None-Match', etag) if lastmodified:
request.add_header('If-Modified-Since', lastmodified)
request.add_header('Accept-encoding', 'gzip')
opener = urllib2.build_opener(SmartRedirectHandler(), DefaultErrorHandler()) return opener.open(request)
urlparse est un module utile pour, vous l'avez devinez, analyser des URL. Sa fonction principale, appelée également urlparse, prend une URL en paramètre et la découpe en un tuple composé de (schème, domaine, chemin, paramètres, paramètres de la chaîne
de requête et identificateur de fragment). Seul le schème nous intéresse ici, pour nous assurer qu'il s'agit bien d'une URL
HTTP (que urllib2 peut prendre en charge).
Nous nous identifions auprès du serveur HTTP avec la chaîne User-Agent passée par la fonction appelante. Si aucune chaîne User-Agent n'a été passée en paramètre, nous utilisons la valeur par défaut définie plus haut dans le module openanything.py. Nous n'utilisons jamais la valeur par défaut définie par urllib2.
Si nous avons une code de hachage ETag, nous l'envoyons dans l'en-tête If-None-Match.
Si nous avons une date de dernière modification, nous l'envoyons dans l'en-tête If-Modified-Since.
Nous indiquons au serveur que nous souhaitons des données compressées.
Nous construisons un opener d'URL qui utilise les deux gestionnaires d'URL spécialisés : SmartRedirectHandler pour gérer les redirections 301 et 302 et DefaultErrorHandler pour gérer les codes 304, 404 et les autres erreurs.
Et voilà ! Nous ouvrons l'URL et retournons un objet-fichier à l'appelant.
Exemple 11.18. La fonction fetch
Cette fonction est définie dans openanything.py.
def fetch(source, etag=None, last_modified=None, agent=USER_AGENT):
'''Fetch data and metadata from a URL, file, stream, or string'''
result = {}
f = openAnything(source, etag, last_modified, agent)
result['data'] = f.read() if hasattr(f, 'headers'):
# save ETag, if the server sent one
result['etag'] = f.headers.get('ETag') # save Last-Modified header, if the server sent one
result['lastmodified'] = f.headers.get('Last-Modified') if f.headers.get('content-encoding', '') == 'gzip': # data came back gzip-compressed, decompress it
result['data'] = gzip.GzipFile(fileobj=StringIO(result['data']])).read()
if hasattr(f, 'url'):
result['url'] = f.url
result['status'] = 200
if hasattr(f, 'status'):
result['status'] = f.status
f.close()
return result
D'abord, nous appelons la fonction openAnything avec une URL, un code de hachage ETag, une date Last-Modified et une chaîne User-Agent.
Nous lisons les données retournées par le serveur. Si elles sont compressées, nous les décompresserons plus tard.
Nous sauvegardons le code de hachage ETag retourné par le serveur pour que l'application appelante puisse nous la passer à nouveau la prochaine fois et que nous la
passions à openAnything, qui la mettra dans l'en-tête If-None-Match et l'enverra au serveur distant.
Nous sauvegardons aussi la date Last-Modified.
Si le serveur indique qu'il a envoyé des données compressées, nous les décompressons.
Si le serveur nous envoi une URL, nous la sauvegardons et considérons que le code de statut est 200 jusqu'à preuve du contraire.
Si un des gestionnaires d'URL spécialisés a obtenu un code de statut, nous le sauvegardons également.
La toute première fois que nous allons chercher une ressource, nous n'avons pas de code de hachage ETag ni de date Last-Modified, donc nous laissons ces paramètres vides (ce sont des paramètres optionnels).
Ce qui nous est retourné est un dictionnaire contenant les en-têtes, le code de statut HTTP et les données retournées par
le serveur. le module openanything s'occupe de la compression gzip en internet, nous n'avons donc pas à nous en occuper à ce niveau.
Si nous recevons un code de statut 301, c'est une redirection permanente et nous devons mettre à jour notre URL à la nouvelle adresse.
La deuxième fois que nous allons chercher la même ressource, nous avons toutes sortes d'information a passer en argument :
une URL (éventuellement mise à jour), le ETag et la date Last-Modified de la dernière requête et bien sûr la chaîne User-Agent.
Ce qui nous est retourné est à nouveau un dictionnaire, mais les données n'ayant pas changé, nous n'obtenons qu'un code de
statut 304 et aucune données.