python3 jsonrpclib 发送两个不同的冲突内容类型头字段
Posted
技术标签:
【中文标题】python3 jsonrpclib 发送两个不同的冲突内容类型头字段【英文标题】:python3 jsonrpclib sends two different conclicting Content-type header fields 【发布时间】:2021-08-09 22:06:05 【问题描述】:我一直在将一些 Python 2 脚本升级到 Python 3。我使用 2to3 来重构代码。使用 python3 运行,我得到一个异常。只需三行代码,我就能重现问题;
import jsonrpclib
p = jsonrpclib.Server("http://r195/cgi-bin/streamscape_api")
print(p.nodeid())
使用 python2,它可以工作:
$ python rpc.py
[u'3011']
当我用 Python3 运行完全相同的代码时,我得到了这个异常:
$ python3 rpc.py
Traceback (most recent call last):
File "rpc.py", line 6, in <module>
print(p.nodeid())
File "/home/kory/.local/lib/python3.8/site-packages/jsonrpclib/jsonrpc.py", line 265, in __call__
return self.__send(self.__name, kwargs)
File "/home/kory/.local/lib/python3.8/site-packages/jsonrpclib/jsonrpc.py", line 212, in _request
response = self._run_request(request)
File "/home/kory/.local/lib/python3.8/site-packages/jsonrpclib/jsonrpc.py", line 226, in _run_request
response = self.__transport.request(
File "/usr/lib/python3.8/xmlrpc/client.py", line 1153, in request
return self.single_request(host, handler, request_body, verbose)
File "/usr/lib/python3.8/xmlrpc/client.py", line 1183, in single_request
raise ProtocolError(
xmlrpc.client.ProtocolError: <ProtocolError for r195/cgi-bin/streamscape_api: 400 Bad Request>
使用 WireShark,我捕获了 python 脚本和网络服务器之间的流量。唯一的区别是 tje 标头。在 python2 中,thid 是发送到网络服务器的标头;
Host: r195
Accept-Encoding: gzip
User-Agent: jsonrpclib/0.1 (Python 2.7.18)
Content-Type: application/json-rpc
使用python3,标题为:
Host: r195
Accept-Encoding: gzip
Content-Type: text/xml
User-Agent: jsonrpclib/0.1 (Python 3.8.10)
Content-Type: application/json-rpc
请注意,python3 发送两个“Content-Type”标头。使用卷曲
构建一个请求包的头部,问题是“Content-Type: text/xml”。使用没有该内容类型的 curl 发送请求,可以正常工作。
为了确定,作为测试,我从 xmlrpc/client.py 中注释掉了 this line,该脚本现在可以与 python3 一起使用。但是注释掉那条线并不是一个可行的解决方案。我相信网络服务器正在运行 lighttpd 1.4.54。
部分问题是由于 xmlrpc.py 从 python2 更改为 python3 的方式。 send_content() 曾经是添加内容类型标头的那个,而 send_request 只会在 2 中发送请求。
在 3 中,xmlrpc 在 send_request() 中添加了 content-type,这在语义上是不正确的。因此,当 jsonrpclib 重载 send_content() 时,它会添加额外的 content-type 标头。
这个项目:https://github.com/tcalmant/jsonrpclib/tree/master/jsonrpclib 也通过重载 send_request() 来纠正这个问题,并且不添加 content-type 标头,这在重载的 send_content 中是正确的。所以使用它可以解决这个问题。然而,当有重复的内容类型时,为什么 lighttpd 失败的根本问题很奇怪。如果没有答案,我们可以继续忽略,因为大多数客户不会这样做。
我想知道这是python3 jdonrpclib bug还是lighthttpd bug?
【问题讨论】:
【参考方案1】:我想知道这是python3 jdonrpclib bug还是lighthttpd bug?
通过请求发送两个(或更多)不同的 Content-Type 标头绝对是 python 库/库交互中的错误。
但是,为什么 lighttpd 在重复的内容类型时失败的根本问题很奇怪。
不,这并不奇怪。 lighttpd 故意拒绝请求中重复的 Content-Type,并且从 lighttpd 1.3.12(2005 年发布)开始就这样做了。那些重复的 Content-Type 标头在您的无效请求中相互冲突。
您可以设置 lighttpd.conf debug.log-request-header-on-error = "enable"
并且 lighttpd 将在 lighttpd 错误日志中针对无效请求报告以下内容:“duplicate Content-Type header -> 400”
[编辑] 供参考: RFC7231 超文本传输协议 (HTTP/1.1):语义和内容
RFC 7231 Appendix D. Collected ABNF 定义Content-Type = media-type
,允许单个media-type
,而不是变量号。因此,规范不允许重复的 Content-Type
标头。
【讨论】:
以上是关于python3 jsonrpclib 发送两个不同的冲突内容类型头字段的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 python 3x 从两个单独的运行 python 文件发送数据
Python3网络爬虫:利用urllib.urlopen向有道翻译发送数据获得翻译结果