使用Python 3.6.1,请求2.13.0,我得到了所请求的URL的奇怪编码。我在查询字符串中有一个包含中文字符的网址,例如huà 話 用
,它应该% - 编码到hu%C3%A0%20%E8%A9%B1%20%E7%94%A8
甚至hu%C3%A0+%E8%A9%B1+%E7%94%A8
,但由于某种原因,它是%-encoding to { {1}}。这是不正确的。我一直在使用http://r12a.github.io/apps/conversion/页来帮助我处理编码。我还使用了JavaScript hu%C3%83%C2%A0%20%C3%A8%C2%A9%C2%B1%20%C3%A7%C2%94%C2%A8
和PHP encodeURI
,并且没有得到任何我看到Requests库所做的事情。
我做错了,编码到目前为止还没有?
更新: 我查看了Mojibake编码并再次挖掘了Requests库,发现问题所在,但我仍然不确定如何修复它。
我正在使用简单的urlencode
调用对内部服务器进行调用。该呼叫进入服务器并获得重定向响应。重定向页面在标题中有.get(url)
,其中列出的URL是正确的。离开服务器的meta charset="UTF-8"
标题是可以的;它被编码为UTF-8,location
标题上有Content-Type
。但是,当我在Python中调试重定向响应时,我注意到响应对象上的标头不正确,似乎没有正确解码。 charset=UTF-8
属性在headers
:location
中包含此属性。如上所述,它应解码为:huÃ\xa0 話 ç\x94
。因此,那个奇怪的URL查询字符串得到了由请求编码的百分比,并被设置回服务器,服务器然后拒绝该URL(显然)。
我能做些什么来防止请求搞砸了吗?或者让它正确解码huà 話 用
标题? Web浏览器似乎没有这个问题。
答案 0 :(得分:4)
您有Mojibake个编码。编码的字节是UTF-8字节的Latin-1解释:
>>> from urllib.parse import quote
>>> text = 'huà 話 用'
>>> quote(text)
'hu%C3%A0%20%E8%A9%B1%20%E7%94%A8'
>>> quote(text.encode('utf8').decode('latin1'))
'hu%C3%83%C2%A0%20%C3%A8%C2%A9%C2%B1%20%C3%A7%C2%94%C2%A8'
您可以通过再次手动编码为Latin-1,然后从UTF-8解码来反转该过程:
>>> unquote('hu%C3%83%C2%A0%20%C3%A8%C2%A9%C2%B1%20%C3%A7%C2%94%C2%A8').encode('latin1').decode('utf8')
'huà 話 用'
或者您可以使用ftfy
library自动修复错误的编码(ftfy
通常可以做得更好,尤其是当Mopibake中涉及Windows代码页时):
>>> from ftfy import fix_text
>>> fix_text(unquote('hu%C3%83%C2%A0%20%C3%A8%C2%A9%C2%B1%20%C3%A7%C2%94%C2%A8'))
'huà 話 用'
你这是关于网址的来源说的:
离开服务器的位置标头正常;它被编码为UTF-8
那是你的问题,就在那里。 HTTP标头始终编码为Latin-1 (*)。服务器必须将Location头设置为完全百分比编码的URL,以便所有UTF-8字节都表示为%HH
转义序列。这些只是ASCII字符,完全保存在Latin-1上下文中。
如果您的服务器将标头作为未转义的UTF-8字节发送,那么HTTP客户端(包括requests
)将解码为Latin-1而不是导致您观察到的确切的Mojibake问题。并且因为URL包含无效的URL字符,requests
将Mojibake结果转义为百分比编码版本。
(*)实际上,Location
标头应该是absoluteURI
as per RFC2396,它始终是ASCII(7位)干净数据,但是因为其他一些HTTP标头允许“描述性”文本,Latin-1(ISO-8859-1)是标题数据的可接受默认编码。请参阅TEXT
rule in section 2.2 of the HTTP/1.1 RFC,在解码任何标头中的非ASCII数据时,requests
最终解码Location
标头的http.client
module遵循此RFC。只有按the Message Header Extensions RFC 2047包装时才能提供非Latin-1数据,但这不适用于[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\W32Time\TimeProviders\NtpClient]
"SpecialPollInterval"=dword:0000012c
标题。