我正在尝试定期请求服务器获取数据。由于数据不经常变化,我决定添加If-None-Match
标头以优化性能。问题是即使ETag
仍然相同,我仍然会获得200
状态代码而不是304
。这是我写的一个小脚本来验证它:
修改:
import requests
headers = {'Accept':'application/json', 'Content-Type':'application/json', 'Authorization':'Bearer XXXX'}
url = "https://api.producthunt.com/v1/posts/12330"
req = None
response_data = None
for i in range(1,10):
if req:
headers = {'Accept':'application/json', 'Authorization':'Bearer XXXX', 'If-None-Match': req.headers['ETag']}
print req.request.headers.get('If-None-Match', 'Not set') # set
req = requests.get(url, headers = headers)
if response_data:
print sorted(req.json().items()) == sorted(response_data.items()) # always True
response_data = req.json()
print req.history # []
print req.status_code # always 200
ETag
标题已设置。req.history
始终返回空列表。Content-Type
标题,但回复仍为200
。2.5.0
。答案 0 :(得分:1)
所以可能会发生一些事情:
您实际上可能不会添加ETag
标头。您应该在请求后检查您是否正在使用req.request.headers.get('If-None-Match', 'Not set')
。在第一次请求之后,它永远不会返回'Not set'
服务返回的表示可能正在更改。我最近帮助某人使用GitHub API调试类似的东西(它们包括一个不同资源的简短表示,其中有一个属性可以改变并使ETag无效)。您应该检查每次返回给您的数据是否完全相同。
检查req.history
以确保没有可能导致问题的重定向
在没有请求正文的GET
请求中,您不应指定Content-Type
。没有内容,因此不应该有内容类型。 (从技术上讲,服务器不应该受到它的困扰,但服务器是变化无常的东西,没有人知道它们会如何响应。)
除此之外,您能否提供您正在使用的请求版本?
答案 1 :(得分:0)
我在这个答案上迟到了 7 年,但我最近遇到了类似的问题,并通过执行以下操作修复了它:
假设您向 https://api.github.com/repos/gnuradio/gnuradio
发出请求,然后您得到以下响应:
HTTP/1.1 200 OK
Server: GitHub.com
Date: Sun, 20 Jun 2021 11:49:40 GMT
Content-Type: application/json; charset=utf-8
Cache-Control: public, max-age=60, s-maxage=60
Vary: Accept, Accept-Encoding, Accept, X-Requested-With
ETag: W/"113b7fb72c9708d155f1482480a4eb374ebeeedfb81abb01e4d087fd4b896910"
Last-Modified: Sun, 20 Jun 2021 10:32:21 GMT
X-GitHub-Media-Type: unknown, github.v3
Access-Control-Expose-Headers: ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, Deprecation, Sunset
Access-Control-Allow-Origin: *
Strict-Transport-Security: max-age=31536000; includeSubdomains; preload
X-Frame-Options: deny
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin
Content-Security-Policy: default-src 'none'
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 1623295573
X-RateLimit-Resource: core
X-RateLimit-Used: 1
Accept-Ranges: bytes
Content-Length: 6534
X-GitHub-Request-Id: 059B:55A2:13A83A:298733:60D0C1F8
connection: close
从那里开始,我必须将 If-None-Match
请求标头设置为上一个响应中收到的 ETag
标头的值。
我还将 If-Modified-Since
请求标头设置为先前响应中收到的 Last-Modified
标头的值。
在python中设置这两个请求头如下:
headers = {}
h1 = {'If-None-Match': 'W/"113b7fb72c9708d155f1482480a4eb374ebeeedfb81abb01e4d087fd4b896910"'}
h2 = {'If-Modified-Since': 'Sun, 20 Jun 2021 10:32:21 GMT'}
headers.update(h1)
headers.update(h2)
response = requests.get('https://api.github.com/repos/gnuradio/gnuradio', headers=headers)
print(response.status_code, response.reason)
这将打印 304 'Not Modified'
注意:请求头中 ETag 值前的 W/
表示使用了“弱验证器”。我不确定这是否总是需要,但 GitHub 似乎实现了它,所以使用它不会有什么坏处。