即使在添加ETag标头后也没有获得304响应

时间:2014-12-23 13:48:45

标签: python rest http http-headers python-requests

我正在尝试定期请求服务器获取数据。由于数据不经常变化,我决定添加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
  1. ETag标题已设置。
  2. 返回的响应数据始终相同。
  3. 没有重定向,因为req.history始终返回空列表。
  4. 我已删除Content-Type标题,但回复仍为200
  5. 我使用的请求版本为2.5.0

2 个答案:

答案 0 :(得分:1)

所以可能会发生一些事情:

  1. 您实际上可能不会添加ETag标头。您应该在请求后检查您是否正在使用req.request.headers.get('If-None-Match', 'Not set')。在第一次请求之后,它永远不会返回'Not set'

  2. 服务返回的表示可能正在更改。我最近帮助某人使用GitHub API调试类似的东西(它们包括一个不同资源的简短表示,其中有一个属性可以改变并使ETag无效)。您应该检查每次返回给您的数据是否完全相同。

  3. 检查req.history以确保没有可能导致问题的重定向

  4. 在没有请求正文的GET请求中,您不应指定Content-Type。没有内容,因此不应该有内容类型。 (从技术上讲,服务器不应该受到它的困扰,但服务器是变化无常的东西,没有人知道它们会如何响应。)

  5. 除此之外,您能否提供您正在使用的请求版本?

答案 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 标头的值。

    • 不是 100% 确定是否总是需要这个标头,我看到的文档中没有提到它,但是当它没有设置时,它似乎在 python 中不起作用,但它可以在不设置的情况下工作使用 curl 命令。
  • 在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 似乎实现了它,所以使用它不会有什么坏处。