Faire des tests d'API et essayer de créer une fonction qui, étant donné une URL entrée, retournera la réponse json, mais si une erreur HTTP est la réponse, un message d'erreur sera retourné.
J'utilisais urllib2 auparavant, mais j'essaie maintenant d'utiliser les requêtes à la place. Cependant, il semble que mon bloc except ne soit jamais exécuté, quelle que soit l'erreur.
testURL = 'http://httpbin.org/status/404'
def return_json(URL):
try:
response = requests.get(URL)
json_obj = response.json()
return json_obj
except requests.exceptions.HTTPError as e:
return "Error: " + str(e)
Le résultat que j'obtiens en exécutant ce qui précède ...
<Response [404]>
Si vous souhaitez que la réponse lève une exception pour un code d'état autre que 200, utilisez response.raise_for_status()
. Votre code ressemblerait alors à:
testURL = 'http://httpbin.org/status/404'
def return_json(URL):
response = requests.get(testURL)
try:
response.raise_for_status()
except requests.exceptions.HTTPError as e:
# Whoops it wasn't a 200
return "Error: " + str(e)
# Must have been a 200 status code
json_obj = response.json()
return json_obj
Vous pouvez dire que c'est clairement plus simple que les autres solutions ici et ne vous oblige pas à vérifier le code d'état manuellement. Vous attraperiez aussi juste un HTTPError
puisque c'est ce que raise_for_status
augmentera. Attraper RequestsException
est une mauvaise idée. Cela va attraper des choses comme ConnectionError
s ou TimeoutError
s, etc. Aucune de ces choses ne signifie la même chose que ce que vous essayez d'attraper.
Note : Vous devriez plutôt aller avec response.raise_for_status()
comme décrit dans réponse d'Ian ci-dessus ( il est l'un des mainteneurs du module requests
).
La façon dont vous gérez tout cela dépend de ce que vous considérez comme une erreur HTTP. Il y a des codes d'état, mais tout autre que 200
Signifie nécessairement qu'il y a une erreur quelconque.
Comme vous l'avez remarqué, la bibliothèque de requêtes ne prend en compte que ces aspects de la réponse HTTP et ne déclenche pas d'exception. L'état HTTP 302
Signifie par exemple Found
, mais la réponse ne contient pas de corps de réponse mais un en-tête Location
à la place que vous devez suivre pour accéder à la ressource vous vouliez vraiment.
Donc, vous voudrez regarder response.status_code
, et faire votre traitement de cela, tout en détectant les erreurs de protocole réelles avec un try..except
. Lorsque vous attrapez ceux-ci, vous devez réellement attraper requests.exceptions.RequestException
, Car il s'agit de la classe de base pour toutes les autres exceptions que le module requests
déclenche.
Voici donc un exemple qui illustre les trois cas:
200 OK
200
import requests
test_urls = ['http://httpbin.org/user-agent',
'http://httpbin.org/status/404',
'http://httpbin.org/status/500',
'httpx://invalid/url']
def return_json(url):
try:
response = requests.get(url)
# Consider any status other than 2xx an error
if not response.status_code // 100 == 2:
return "Error: Unexpected response {}".format(response)
json_obj = response.json()
return json_obj
except requests.exceptions.RequestException as e:
# A serious problem happened, like an SSLError or InvalidURL
return "Error: {}".format(e)
for url in test_urls:
print "Fetching URL '{}'".format(url)
print return_json(url)
print
Production:
Fetching URL 'http://httpbin.org/user-agent'
{u'user-agent': u'python-requests/2.1.0 CPython/2.7.1 Darwin/11.4.2'}
Fetching URL 'http://httpbin.org/status/404'
Error: Unexpected response <Response [404]>
Fetching URL 'http://httpbin.org/status/500'
Error: Unexpected response <Response [500]>
Fetching URL 'httpx://invalid/url'
Error: No connection adapters were found for 'httpx://invalid/url'
Il peut également y avoir une exception déclenchée par response.json()
si vous obtenez une réponse réussie, mais ce n'est tout simplement pas JSON - vous voudrez peut-être également en tenir compte.
Remarque : Le bit if not response.status_code // 100 == 2
Fonctionne comme ceci: L'opérateur //
Fait ce qu'on appelle division au sol , donc il arrondit à l'entier suivant (c'est le comportement par défaut pour le /
dans Python 2.x, mais pas Python 3.x, qui a changé /
Pour faire une division en virgule flottante). Donc status // 100 == 2
Est vrai pour tous les codes 2xx
.
Vous pouvez vérifier le response.status_code
valeur. Si ce n'est pas 200
, vous pouvez alors considérer qu'il s'agit d'une condition d'erreur et lever votre propre exception.