40

做一些 API 测试并尝试创建一个给定输入 URL 的函数,它将返回 json 响应,但是如果响应是 HTTP 错误,则会返回错误消息。

我之前使用的是 urllib2,但现在尝试使用 requests 代替。但是,无论错误如何,我的 except 块似乎都不会执行。

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)

我从上面运行得到的结果......

<Response [404]>
4

3 回答 3

72

如果您希望响应引发非 200 状态代码的异常,请使用response.raise_for_status(). 您的代码将如下所示:

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

您可以看出这显然比此处的其他解决方案更简单,并且不需要您手动检查状态代码。你也可以抓到一个,HTTPError因为那是raise_for_status会加注的。抓RequestsException是个坏主意。这将捕获诸如ConnectionErrors 或TimeoutErrors 之类的东西。这些都与您要捕获的内容不同。

于 2014-07-02T12:53:54.223 回答
19

注意:您应该按照上面Ian 的回答response.raise_for_status()中的描述进行(他是模块的维护者之一)。requests


你如何处理这一切取决于你认为什么是 HTTP 错误。有状态代码,但并非所有内容都200必然意味着存在某种错误。

如您所见,请求库仅考虑 HTTP 响应的另一方面,不会引发异常。302例如, HTTP 状态表示Found,但响应不包含响应正文,而是包含Location标题,而不是您需要遵循的标题才能获取您真正想要的资源。

因此,您需要查看response.status_code并进行处理,同时使用try..except. 当捕获那些你应该实际捕获的东西requests.exceptions.RequestException时,因为这是模块引发的所有其他异常的基类。requests

所以这是一个演示所有三种情况的示例:

  • 成功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

输出:

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'

如果您得到一个成功的响应,也可能会引发一个异常response.json(),但它根本不是 JSON - 所以您可能也想考虑这一点。


注意:该if not response.status_code // 100 == 2位的工作方式如下://运算符执行所谓的floor 除法,因此它向下舍入到下一个整数(这是/Python 2.x 中的默认行为,但不是 Python 3.x,它更改/为浮点除法)。所以status // 100 == 2适用于所有2xx代码。

于 2014-07-01T21:18:20.477 回答
1

您可以检查该response.status_code值。如果不是200,那么您可以将其视为错误条件并抛出您自己的异常。

于 2014-07-01T20:46:48.793 回答