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

URL编码Unicode字符的正确方法是什么?,unicode,utf-8,character-encoding,urlencode,web-standards,Unicode,Utf 8,Character Encoding,Urlencode,Web Standards,我知道非标准的%uxxx方案,但这似乎不是一个明智的选择,因为该方案已被W3C拒绝 一些有趣的例子: 心的性格。 如果我在浏览器中键入: http://www.google.com/search?q=♥ 然后复制粘贴,我看到这个URL http://www.google.com/search?q=%E2%99%A5 这使得Firefox(或Safari)似乎正在这样做 urllib.quote_plus(x.encode("latin-1")) '%E2%99%A5' 这是有道理的,除了不

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

一些有趣的例子:

心的性格。 如果我在浏览器中键入:

http://www.google.com/search?q=♥
然后复制粘贴,我看到这个URL

http://www.google.com/search?q=%E2%99%A5
这使得Firefox(或Safari)似乎正在这样做

urllib.quote_plus(x.encode("latin-1"))
'%E2%99%A5'
这是有道理的,除了不能用拉丁语-1编码的东西,比如三点字符

如果我键入URL

http://www.google.com/search?q=…
进入我的浏览器,然后复制和粘贴,我得到

http://www.google.com/search?q=%E2%80%A6
回来。这似乎是做这些事情的结果

urllib.quote_plus(x.encode("utf-8"))
这是有道理的,因为…不能用拉丁语-1编码

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

由于这似乎模棱两可:

In [67]: u"…".encode('utf-8').decode('latin-1')
Out[67]: u'\xc3\xa2\xc2\x80\xc2\xa6'
工作正常,所以我不知道浏览器如何判断是用UTF-8还是拉丁语-1解码


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

我总是用UTF-8编码。从:

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


这似乎是因为过去有其他被接受的URL编码方式,浏览器尝试了几种对URI进行解码的方法,但是如果你是进行编码的人,你应该使用UTF-8。

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


因此,除非您有充分的理由使用许多其他编码方案中的一种,否则请使用utf-8。

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

如果您只是在URL栏中输入一个URL,那么浏览器就没有一个要处理的基页,因此只能猜测。因此,在本例中,它似乎一直在执行utf-8(因为两个输入都产生了三个八位组形式的值)

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


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

IRI()是取代URI/URL(以及更旧的)标准的最新标准。URI/URL本机不支持Unicode(好吧,增加了对未来基于URI/URL的协议的规定以支持它,但不更新过去的RFC)。“%uxxx”方案是一种非标准扩展,在某些情况下允许使用Unicode,但并非每个人都能普遍实现。另一方面,IRI完全支持Unicode,并要求在对文本进行百分比编码之前将其编码为UTF-8。

IRI不会取代URI,因为在某些上下文(包括HTTP)中只允许使用URI(实际上是ASCII)


相反,你可以指定一个IRI,当你上网时它会被转换成一个URI。

UTF-8也应该被使用,因为它是替代旧URL标准的新的IRI标准(RFC 3987)所允许的唯一编码。如果其他人像我一样惊讶,@RemyLebeau评论中的文本提到了RFC3987,但是链接到了旧的规范3896。正确的网址显然是对的,很抱歉。URI是由RFC 3986定义的,IRI是由RFC 3987定义的。RFC 3987()定义了一种标准编码-当编码不允许未编码的字符时,必须使用UTF-8。两个示例都被编码为UTF-8。第一个肯定不是拉丁语-1,因为它有三个字节长…%E2%99%A5是十六进制的字节值。黑心不是的一部分。要准确地了解浏览器的编码方式和内容(以及许多其他有用信息),请使用大多数现代浏览器中内置的开发工具,或获得免费的HTTP调试器,如。我希望看到协议的更新,以便URL中完全支持unicode,不仅通过percent-encoding.IRIs允许使用未编码的Unicode字符,少数情况下必须对保留字符进行编码。