我正在尝试确定它是否是 Python 的 urllib.urlopen() 的错误函数在发出简单的 REST API 请求时省略了 HTTP Accept header 。
Facebook Graph API似乎注意到标题是否存在:
GET /zuck HTTP/1.0
Host: graph.facebook.com
Accept: */*
没有accept头,application/json返回的content-type; charset=UTF-8
变为 text/javascript;字符集=UTF-8
。这可能是 Facebook 的 REST API 中的错误,也可能是对缺少接受 header 的合法响应。
我注意到像 curl 这样的命令行工具默认使用 Accept: */*
:
$ curl -v https://graph.facebook.com/zuck
> GET /zuck HTTP/1.1
> User-Agent: curl/7.30.0
> Host: graph.facebook.com
> Accept: */*
同样,Python requests package还使用 Accept: */*
作为默认值:
def default_headers():
return CaseInsensitiveDict({
'User-Agent': default_user_agent(),
'Accept-Encoding': ', '.join(('gzip', 'deflate')),
'Accept': '*/*',
'Connection': 'keep-alive',
})
我认为 curl 和 requests 添加默认值是有原因的,但我不确定是什么原因。
RFC 2616对于 HTTP/1.1,*/* 表示所有媒体类型
并且如果不存在 Accept header 字段,则假定客户端接受所有媒体类型
。这似乎表明 Accept: */*
是可选的,省略它不会有任何效果。也就是说,Python 使用的是 HTTP/1.0,而 RFC 并未提及省略 header 的影响。
我想确定最佳做法是像 curl 和 requests 那样包含 Accept: */*
还是它是否是可以省略,就像 Python 的 urllib.urlopen() 一样。
这个问题很重要,因为我可以 fix urllib.urlopen()如果它被确定为有问题,或者如果它与通常使用 HTTP/1.0 实现的 REST API 一起使用时有问题:
>>> import httplib
>>> httplib.HTTPConnection.debuglevel = 1
>>> import urllib
>>> u = urllib.urlopen('https://graph.facebook.com/zuck')
send: 'GET /zuck HTTP/1.0\r\nHost: graph.facebook.com\r\nUser-Agent: Python-urllib/1.17\r\n\r\n'
StackOverflow 上的相关问题对本题没有帮助。 What does 'Accept: */*' mean under Client section of Request Headers?询问 */*
是什么意思(我们已经知道它表示所有媒体类型)和 Send a curl request with no Accept header?询问如何在 curl 请求中省略接受 header 。我的问题集中在你是否应该包含 */*
以及忽略它是否是一个错误。
最佳答案
RFC 状态
The Accept request-header field can be used to specify certain media types which are acceptable for the response.
这意味着 header 是可选的,因为它表示可以使用
。
正如您指出的那样,RFC 还说:
If no Accept header field is present, then it is assumed that the client accepts all media types.
这意味着省略 header 应该被服务器等效地解释为发送 Accept: */*
在这两种情况下客户端接受所有媒体类型
.
有趣的是,facebook 的响应在这两种情况下都不同,但我猜这是他们未能正确解释协议(protocol)。尽管在另一方面,这两个响应显然都是对请求的正确响应(我觉得这是一个有趣的转折)。
我对这个问题有一些一般性的想法(也可能是 contribute to the bugfix discussion ):
- 正在关注 Postel Law
在你所做的事情上保持保守,在你从别人那里接受的事情上保持自由(通常改写为“在你发送的东西上保持保守,在你接受的东西上保持自由”)。
你可以决定更精确并显式添加Accept: */*
。您会更准确地帮助服务器,因为他可能误解了协议(protocol)(就像 facebook 可能那样),缺少 header 将等同于Accept: */*
- 仅添加 header 字段,如
Accept: */*
可以省略,每个请求都会增加 11 字节的网络流量,这可能会导致性能问题。将Accept: */*
设为请求中的默认值可能会使开发人员很难将其从 header 中取出以节省 11 字节。 - 规范(或标准)和事实上的标准是有区别的。显然,根据规范省略 header 字段是完美的,另一方面,许多库似乎包含此字段,并且像 facebook API 这样的服务表现不同,这可以被视为正在创建的事实上的标准您可以跳入循环并参与创建循环。
当使用 HTTP/1.1 时:即使 (1) 和 (3) 代表 fixing the urllib我可能会 follow the specification和性能参数 (2) 并省略标题。如上所述,facebook 在这两种情况下的响应都是正确的,因为他们可以将媒体类型设置为他们喜欢的任何类型。 (尽管这种行为看起来是无意的、奇怪的和错误的)
当谈到 HTTP/1.0 时:我会发送接受 header ,因为你说它没有在 HTTP/1.0 RFC 中指定,然后我认为 Postel 定律变得更加重要。另一方面,Accept header 在 http 1.0 中只是可选的. Accept 请求 header 字段可用于指示可接受的媒体范围列表,作为对请求的响应
为什么默认设置可选 header ?
关于python - 在 REST API 的 HTTP/1.0 请求中省略 Accept */* header 是否是错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25961997/