ChatGPT解决这个技术问题 Extra ChatGPT

URL 编码 Unicode 字符的正确方法是什么?

我知道非标准的 %uxxxx 方案,但这似乎不是一个明智的选择,因为该方案已被 W3C 拒绝。

一些有趣的例子:

心脏字符。如果我在浏览器中输入:

http://www.google.com/search?q=♥

然后复制粘贴,我看到了这个网址

http://www.google.com/search?q=%E2%99%A5

这看起来像是 Firefox(或 Safari)正在这样做。

urllib.quote_plus(x.encode("latin-1"))
'%E2%99%A5'

这是有道理的,除了不能用 Latin-1 编码的东西,比如三点字符。

如果我输入网址

http://www.google.com/search?q=…

进入我的浏览器然后复制并粘贴,我得到

http://www.google.com/search?q=%E2%80%A6

背部。这似乎是做的结果

urllib.quote_plus(x.encode("utf-8"))

这是有道理的,因为……不能用 Latin-1 编码。

但是我不清楚浏览器如何知道是用 UTF-8 还是 Latin-1 解码。

因为这似乎是模棱两可的:

In [67]: u"…".encode('utf-8').decode('latin-1')
Out[67]: u'\xc3\xa2\xc2\x80\xc2\xa6'

有效,所以我不知道浏览器如何确定是用 UTF-8 还是 Latin-1 解码。

处理我需要处理的特殊字符的正确做法是什么?

您的两个示例都编码为 UTF-8。第一个肯定不是 Latin-1,因为它是三个字节长......
%E2%99%A5 是 the "black heart suit" in UTF-8 字节值的十六进制。那颗黑色的心不是 Latin-1 character set 的一部分。
要可靠地查看浏览器的编码方式和内容(以及许多其他有用的信息),请使用大多数现代浏览器中内置的开发人员工具,或获取免费的 HTTP 调试器,如 Fiddler

C
Community

我总是用 UTF-8 编码。从 Wikipedia page on percent encoding

通用 URI 语法要求提供 URI 中字符数据表示的新 URI 方案实际上必须表示来自未保留集中的字符而无需翻译,并且应该根据 UTF-8 将所有其他字符转换为字节,然后百分比编码这些值。此要求是在 2005 年 1 月随 RFC 3986 的发布而引入的。在此日期之前引入的 URI 方案不受影响。

似乎因为过去还有其他公认的 URL 编码方法,浏览器尝试了几种解码 URI 的方法,但如果你是编码的人,你应该使用 UTF-8。


还应该使用 UTF-8,因为它是替代旧 URL 标准的新 IRI 标准(RFC 3987,tools.ietf.org/html/rfc3986)允许的唯一编码。
如果其他人像我一样感到惊讶,@RemyLebeau 的评论中的文本提到了 RFC3987,但链接是旧规范 3896。正确的 URL 显然是 tools.ietf.org/html/rfc3987
是的,对此感到抱歉。 URI 由 RFC 3986 定义,IRI 由 RFC 3987 定义。
a
araqnid

一般规则似乎是浏览器根据提供表单的页面的内容类型对表单响应进行编码。这是一个猜测,如果服务器向我们发送“text/xml; charset=iso-8859-1”,那么他们期望以相同格式返回响应。

如果您只是在 URL 栏中输入 URL,则浏览器没有可处理的基本页面,因此只能猜测。因此,在这种情况下,它似乎一直在执行 utf-8(因为您的两个输入都产生了三个八位字节形式的值)。

可悲的事实是,AFAIK 对于查询字符串中的值或 URL 中的任何字符应该解释为什么字符集没有标准。至少在查询字符串中的值的情况下,没有理由假设它们一定对应于字符。

这是一个已知问题,您必须告诉服务器框架您希望查询字符串编码为哪个字符集——例如,在 Tomcat 中,您必须先调用 request.setEncoding() (或一些类似的方法)调用任何 request.getParameter() 方法。关于这个主题的文档缺乏可能反映了许多开发人员对这个问题缺乏认识。 (我经常问 Java 面试者 Reader 和 InputStream 的区别是什么,而且经常会得到空白)


RFC 3987 (tools.ietf.org/html/rfc3986) 定义了一种标准编码 - 对不允许未编码的字符进行编码时必须使用 UTF-8。
R
Remy Lebeau

IRI (RFC 3987) 是取代 URI/URL(RFC 3986 和更早版本)标准的最新标准。 URI/URL 本身并不支持 Unicode(好吧,RFC 3986 添加了未来基于 URI/URL 的协议的规定以支持它,但不更新过去的 RFC)。 "%uXXXX" 方案是在某些情况下允许 Unicode 的非标准扩展,但并非所有人都普遍实施。另一方面,IRI 完全支持 Unicode,并要求在进行百分比编码之前将文本编码为 UTF-8。


我希望看到协议的更新,以便在 URL 中完全支持 unicode,而不仅仅是通过百分比编码。
IRI 允许使用未编码的 Unicode 字符,但保留字符必须编码的少数情况除外。
M
Mark Nottingham

IRI 不会替换 URI,因为在某些情况下(包括 HTTP)只允许使用 URI(实际上是 ASCII)。

取而代之的是,您指定一个 IRI,它会在上网时转换为一个 URI。


P
Pat O

第一个问题是你的需求是什么? UTF-8 编码是使用廉价编辑器创建的文本和支持多种语言之间的一个很好的折衷。关于识别编码的浏览器,响应(来自网络服务器)应该告诉浏览器编码。大多数浏览器仍然会尝试猜测,因为在很多情况下这要么是缺失的,要么是错误的。他们通过读取一些结果流来猜测是否存在不适合默认编码的字符。目前所有浏览器(?我没有检查这个,但它非常接近真实)使用 utf-8 作为默认值。

因此,请使用 utf-8,除非您有令人信服的理由使用许多其他编码方案之一。