python 3.7 urllib.request 不遵循重定向 URL
python 3.7 urllib.request doesn't follow redirect URL
我正在使用 Python 3.7 和 urllib。
一切正常,但当它收到 http 重定向请求 (307) 时似乎不会自动重定向。
这是我得到的错误:
ERROR 2020-06-15 10:25:06,968 HTTP Error 307: Temporary Redirect
我必须用 try-except 来处理它并手动向新位置发送另一个请求:它工作正常但我不喜欢它。
这些是我用来执行请求的代码片段:
req = urllib.request.Request(url)
req.add_header('Authorization', auth)
req.add_header('Content-Type','application/json; charset=utf-8')
req.data=jdati
self.logger.debug(req.headers)
self.logger.info(req.data)
resp = urllib.request.urlopen(req)
url 是一个 https 资源,我设置了一个带有一些授权信息的 header 和 content-type。
req.data 是一个 JSON
从 urllib 文档我了解到重定向是由库本身自动执行的,但它对我不起作用。它总是引发 http 307 错误并且不遵循重定向 URL。
我也尝试过使用 opener 指定默认的重定向处理程序,但结果相同
opener = urllib.request.build_opener(urllib.request.HTTPRedirectHandler)
req = urllib.request.Request(url)
req.add_header('Authorization', auth)
req.add_header('Content-Type','application/json; charset=utf-8')
req.data=jdati
resp = opener.open(req)
可能是什么问题?
重定向未自动完成的原因已被您在评论部分的讨论中正确识别。具体来说,RFC 2616, Section 10.3.8 指出:
If the 307 status code is received in response to a request other
than GET or HEAD, the user agent MUST NOT automatically redirect the
request unless it can be confirmed by the user, since this might
change the conditions under which the request was issued.
回到问题 - 鉴于 data
已分配,这会自动导致 get_method
返回 POST
(根据 [=19= 的 how this method was implemented), and since that the request method is POST
, and the response code is 307
, an HTTPError
is raised instead as per the above specification. In the context of Python's urllib
, this specific section ] 模块引发异常。
要进行实验,请尝试以下代码:
import urllib.request
import urllib.parse
url = 'http://httpbin.org/status/307'
req = urllib.request.Request(url)
req.data = b'hello' # comment out to not trigger manual redirect handling
try:
resp = urllib.request.urlopen(req)
except urllib.error.HTTPError as e:
if e.status != 307:
raise # not a status code that can be handled here
redirected_url = urllib.parse.urljoin(url, e.headers['Location'])
resp = urllib.request.urlopen(redirected_url)
print('Redirected -> %s' % redirected_url) # the original redirected url
print('Response URL -> %s ' % resp.url) # the final url
运行 原样的代码可能会产生以下内容
Redirected -> http://httpbin.org/redirect/1
Response URL -> http://httpbin.org/get
请注意,随后重定向到 get
是自动完成的,因为后续请求是 GET
请求。注释掉 req.data
分配行将导致缺少“重定向”输出行。
在异常处理块中需要注意的其他值得注意的事情,e.read()
可以用来检索服务器生成的响应 body 作为 HTTP 307
响应的一部分(因为 data
已发布,响应中可能有一个可以处理的短实体?),并且 urljoin
是必需的,因为 Location
header 可能是相对的 URL(或只是缺少主机)到后续资源。
此外,出于兴趣(以及出于链接目的),这个特定问题之前已被多次询问,我很惊讶他们从未得到任何答案,如下所示:
我正在使用 Python 3.7 和 urllib。 一切正常,但当它收到 http 重定向请求 (307) 时似乎不会自动重定向。
这是我得到的错误:
ERROR 2020-06-15 10:25:06,968 HTTP Error 307: Temporary Redirect
我必须用 try-except 来处理它并手动向新位置发送另一个请求:它工作正常但我不喜欢它。
这些是我用来执行请求的代码片段:
req = urllib.request.Request(url)
req.add_header('Authorization', auth)
req.add_header('Content-Type','application/json; charset=utf-8')
req.data=jdati
self.logger.debug(req.headers)
self.logger.info(req.data)
resp = urllib.request.urlopen(req)
url 是一个 https 资源,我设置了一个带有一些授权信息的 header 和 content-type。 req.data 是一个 JSON
从 urllib 文档我了解到重定向是由库本身自动执行的,但它对我不起作用。它总是引发 http 307 错误并且不遵循重定向 URL。 我也尝试过使用 opener 指定默认的重定向处理程序,但结果相同
opener = urllib.request.build_opener(urllib.request.HTTPRedirectHandler)
req = urllib.request.Request(url)
req.add_header('Authorization', auth)
req.add_header('Content-Type','application/json; charset=utf-8')
req.data=jdati
resp = opener.open(req)
可能是什么问题?
重定向未自动完成的原因已被您在评论部分的讨论中正确识别。具体来说,RFC 2616, Section 10.3.8 指出:
If the 307 status code is received in response to a request other than GET or HEAD, the user agent MUST NOT automatically redirect the request unless it can be confirmed by the user, since this might change the conditions under which the request was issued.
回到问题 - 鉴于 data
已分配,这会自动导致 get_method
返回 POST
(根据 [=19= 的 how this method was implemented), and since that the request method is POST
, and the response code is 307
, an HTTPError
is raised instead as per the above specification. In the context of Python's urllib
, this specific section ] 模块引发异常。
要进行实验,请尝试以下代码:
import urllib.request
import urllib.parse
url = 'http://httpbin.org/status/307'
req = urllib.request.Request(url)
req.data = b'hello' # comment out to not trigger manual redirect handling
try:
resp = urllib.request.urlopen(req)
except urllib.error.HTTPError as e:
if e.status != 307:
raise # not a status code that can be handled here
redirected_url = urllib.parse.urljoin(url, e.headers['Location'])
resp = urllib.request.urlopen(redirected_url)
print('Redirected -> %s' % redirected_url) # the original redirected url
print('Response URL -> %s ' % resp.url) # the final url
运行 原样的代码可能会产生以下内容
Redirected -> http://httpbin.org/redirect/1
Response URL -> http://httpbin.org/get
请注意,随后重定向到 get
是自动完成的,因为后续请求是 GET
请求。注释掉 req.data
分配行将导致缺少“重定向”输出行。
在异常处理块中需要注意的其他值得注意的事情,e.read()
可以用来检索服务器生成的响应 body 作为 HTTP 307
响应的一部分(因为 data
已发布,响应中可能有一个可以处理的短实体?),并且 urljoin
是必需的,因为 Location
header 可能是相对的 URL(或只是缺少主机)到后续资源。
此外,出于兴趣(以及出于链接目的),这个特定问题之前已被多次询问,我很惊讶他们从未得到任何答案,如下所示: