【问题标题】:Why does Python's urllib2.urlopen() raise an HTTPError for successful status codes?为什么 Python 的 urllib2.urlopen() 会为成功的状态码引发 HTTPError?
【发布时间】:2011-10-25 08:42:27
【问题描述】:

根据the urllib2 documentation

由于默认处理程序处理重定向(300 范围内的代码),而 100-299 范围内的代码表示成功,您通常只会看到 400-599 范围内的错误代码。

还有下面的代码

request = urllib2.Request(url, data, headers)
response = urllib2.urlopen(request)

使用代码 201(已创建)引发 HTTPError:

ERROR    2011-08-11 20:40:17,318 __init__.py:463] HTTP Error 201: Created

那么为什么urllib2 在这个成功的请求上抛出 HTTPErrors?

这不是太痛苦;我可以轻松地将代码扩展为:

try:
    request = urllib2.Request(url, data, headers)
    response = urllib2.urlopen(request)
except HTTPError, e:
    if e.code == 201:
        # success! :)
    else:
        # fail! :(
else:
    # when will this happen...?

但这似乎不是预期的行为,基于文档和我找不到关于这种奇怪行为的类似问题的事实。

另外,else 块应该期待什么? 如果成功的状态码都被解释为HTTPErrors,那么urllib2.urlopen() 什么时候只返回一个普通的文件状响应对象就像所有 urllib2 文档所指的一样?

【问题讨论】:

  • 在 201-299 之间看到响应代码真的很不寻常。 urllib2 没有完美地处理它们并不奇怪。
  • 我错过了什么吗? 201 对我来说很好用……
  • @Santa,根据 dcrosta 的回答,也许您使用的是非标准处理程序?
  • @Leopd:确实如此。查看 Python27\Lib 中的当前 urllib2.py 源代码,第 511-3 行。
  • try块成功执行时,最后的else语句将被执行——如果有帮助的话,你可以把它读成if exception: else:

标签: python urllib2 http-status-codes


【解决方案1】:

您可以编写自定义Handler 类以与urllib2 一起使用,以防止特定错误代码被引发为HTTError。这是我以前用过的一个:

class BetterHTTPErrorProcessor(urllib2.BaseHandler):
    # a substitute/supplement to urllib2.HTTPErrorProcessor
    # that doesn't raise exceptions on status codes 201,204,206
    def http_error_201(self, request, response, code, msg, hdrs):
        return response
    def http_error_204(self, request, response, code, msg, hdrs):
        return response
    def http_error_206(self, request, response, code, msg, hdrs):
        return response

然后你可以像这样使用它:

opener = urllib2.build_opener(self.BetterHTTPErrorProcessor)
urllib2.install_opener(opener)

req = urllib2.Request(url, data, headers)
urllib2.urlopen(req)

【讨论】:

    【解决方案2】:

    正如实际的库文档所述:

    对于200个错误码,立即返回响应对象。

    对于非 200 错误代码,这只是通过 OpenerDirector.error() 将作业传递给 protocol_error_code 处理程序方法。最终,如果没有其他处理程序处理错误,urllib2.HTTPDefaultErrorHandler 将引发 HTTPError。

    http://docs.python.org/library/urllib2.html#httperrorprocessor-objects

    【讨论】:

      【解决方案3】:

      我个人认为将其作为默认行为是一个错误并且非常不直观。 确实,非 2XX 代码意味着协议级别的错误,但是将其变成异常就太远了(至少在我看来)。

      无论如何,我认为避免这种情况最优雅的方法是:

      opener = urllib.request.build_opener()
      for processor in opener.process_response['https']: # or http, depending on what you're using
         if isinstance(processor, urllib.request.HTTPErrorProcessor): # HTTPErrorProcessor also for https
             opener.process_response['https'].remove(processor)
             break # there's only one such handler by default
      response = opener.open('https://www.google.com')
      

      现在你有了响应对象。您可以查看它的状态码、标题、正文等。

      【讨论】:

        猜你喜欢
        • 2019-06-12
        • 1970-01-01
        • 1970-01-01
        • 2013-01-27
        • 1970-01-01
        • 1970-01-01
        • 2012-07-12
        • 2016-05-02
        • 1970-01-01
        相关资源
        最近更新 更多