作者:孙东国
标准参考
URI 的组成如下所示:
foo://example.com:8042/over/there?name=ferret#nose
\_/ \______________/\_________/ \_________/ \__/
| | | | |
scheme authority path query fragment
| _____________________|__
/ \ / \
urn:example:animal:ferret:nose
根据 HTML 4.01 规范中的描述,URI 中不应该包含非 ASCII 字符。如以下 href 属性的值是不合法的:
<A href="http://foo.org/Håkon">...</A>
规范中建议,用户端在这种情况下应采取以下方式处理非 ASCII 字符:
- 将每个字符转换为 UTF-8 编码的相同字符,每个字符将有一或多个字节。
- 用 URI 编码机制对这些字节进行编码。如:每个字节转换为 %HH,其中的 HH 为这些字节的值的十六进制表示。这种方式称为“百分号编码”。
关于 URI 类型及 URI 属性值中的非 ASCII 字符(Non-ASCII characters in URI attribute values)的详细信息,请参考 HTML4.01 规范 6.4 URIs 及 附录B.2.1 中的内容。
关于“百分号编码”的详细信息,请参考 RFC-3986 2.1. Percent-Encoding 中的内容。
关于 URI 组成的更多信息,请参考 RFC-3986 3. Syntax Components 中的内容。
问题描述
对于 URI 中非 ASCII 字符,并非所有浏览器都是按照 HTML 4.01 规范中的建议实现的,而且不同浏览器在处理不同形式的 URI 时,表现也有差异。
造成的影响
这个问题将导致在服务端或客户端通过代码获取 URI 中的非 ASCII 字符信息时无法分辨编码信息,并产生乱码。
受影响的浏览器
问题分析
下面测试各种情况下各浏览器对于 URI 中非 ASCII 字符的编码方式。
在应用中经常使用的编码是 GB2312 和 UTF-8,一个汉字在 GB2312 编码下占 2 个字节,在 UTF-8 编码下占 3 个字节,因此通过对比这两种编码更容易看出区别。下面的例子中将分别使用这两种编码测试。
- 测试使用的非 ASCII 字符均为中文字符“汉”,“汉”在 GB2312 编码中的字节码为“BA BA”,在 UTF-8 编码中的字节码为“E6 B1 89”。
- 测试结果的截图中,所有字符均为 ASCII 编码,GB2312 编码的“汉”以 ASCII 编码显示时,为“ºº”,UTF-8 编码的“汉”以 ASCII 编码显示时,为“æ±ᄆ”(第三个字节在 ASCII 字符集中无对应字符,因此显示为“ᄆ”)。
- 测试的访问地址均为:
http://local.test/BrowserName/汉?汉=汉
1
为了便于区分各浏览器的表现,BrowserName 将在测试中替换为各浏览器名。
- 另外,当声明一段测试代码是 GB2312 编码时,其含义为该 HTML 文件的编码为 GB2312,并且在该文件中声明了:
<meta http-equiv="Content-Type" content="text/html; charset=gb2312"/>
同样,当声明一段测试代码是 UTF-8 编码时,其含义为该 HTML 文件的编码为 UTF-8,并且在该文件中声明了:
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
1. 在浏览器的地址栏直接输入包含非 ASCII 字符的 URI 时
在各浏览器的地址栏中,直接输入“http://local.test/BrowserName/汉?汉=汉
”,结果如下:1

可见,对于 URI 中的非 ASCII 字符:
- 在 path 部分,所有浏览器都使用了 UTF-8 并做了百分比编码。
- 在 query 部分,IE 使用了 GB2312,未做百分比编码;Firefox 和 Opera 使用了 GB2312,做了百分比编码;Chrome 和 Safari 则仍使用 UTF-8 并做了百分比编码。
2. 点击链接跳转或使用脚本跳转到包含非 ASCII 字符的 URI 时
在不同的编码下,测试以下两段代码:
<button onclick="location.href='http://local.test/BrowserName/汉?汉=汉';">go</button>
<a href="http://local.test/BrowserName/汉?汉=汉">go</a>
点击按钮或链接后,各浏览器实际发送的 URI 如下:
GB2312
 |
UTF-8
 |
可见,对于 URI 中的非 ASCII 字符:
- 在 path 部分,所有浏览器都转换为 UTF-8,做了百分比编码。
- 在 query 部分,IE 使用当前编码,未做百分比编码;其他浏览器则使用当前编码做百分比编码。
3. 使用 Ajax 请求包含非 ASCII 字符的 URI 时(get 方法)
在不同的编码下,测试以下代码:
<script>
function go(){
var xhr=window.XMLHttpRequest?new XMLHttpRequest():new ActiveXObject("Microsoft.XMLHTTP");1
xhr.open("get","http://local.test/BrowserName/汉?汉=汉",true);2
xhr.send(null);
}
</script>
<button onclick="go();">go</button>
点击按钮后,各浏览器实际发送的 URI 如下:
GB2312
 |
UTF-8
 |
可见:
- IE 无视页面编码设置,将任意编码的字符转换为 GB2312 发送请求,并且对于 URI 中的非 ASCII 字符处理如下:
- 在 path 部分,IE6 并未处理;IE7 IE8 则做百分比编码。
- 在 query 部分,IE 并未对其处理。
- 其他浏览器对于 URI 中的非 ASCII 字符处理如下:
- 在 path 部分,均转换为 UTF-8 并做百分比编码。
- 在 query 部分,Firefox Opera 转换为 UTF-8 并做百分比编码,Chrome Safari 则使用当前编码做百分比编码。
4. 差异总结
根据以上的测试,总结各浏览器对 URI 中非 ASCII 字符的处理的差异如下:
地址栏直接输入:
浏览器
path 部分
query 部分
使用 UTF-8
百分比编码
使用 UTF-8
百分比编码
IE
是 |
是 |
否 |
否 |
Firefox Opera
是 |
是 |
否 |
是 |
Chrome Safari
是 |
是 |
是 |
是 |
点击链接跳转或使用脚本跳转:
浏览器
path 部分
query 部分
转换为 UTF-8
百分比编码
转换为 UTF-8
百分比编码
IE
是 |
是 |
否使用页面编码
|
否 |
Firefox Chrome Safari Opera
是 |
是 |
否使用页面编码
|
是 |
使用 Ajax 的 get 方法请求:
浏览器
path 部分
query 部分
使用 UTF-8
百分比编码
使用 UTF-8
百分比编码
IE6
否无视页面编码使用 GB2312
|
否 |
否无视页面编码使用 GB2312
|
否 |
IE7 IE8
否无视页面编码使用 GB2312
|
是 |
否无视页面编码使用 GB2312
|
否 |
Firefox Opera
是 |
是 |
是 |
是 |
Chrome Safari
是 |
是 |
否使用页面编码
|
是 |
解决方案
当 URI 中含有非 ASCII 字符时,不要依赖浏览器对 URI 的编码方式,以避免产生差异。建议:
- 在使用此 URI 之前,先对其进行处理,如使用 JS 的 encodeURI 或 encodeURIComponent 方法(JS 的这两个方法会将字符串转换为 UTF-8 并做百分比编码)。
- 在使用 XHR 对象发送 Ajax 请求时,如果仅在 query 部分含有非 ASCII 字符,请使用 post 方法发送,并在 send 之前使用
xhrObject.setRequestHeader("Content-Type","application/x-www-form-urlencoded")
。或者仍使用 get 方法,但在发送前使用 encodeURI 或 encodeURIComponent 方法编码。
- 经过上述处理,在此 URI 的接收端使用 UTF-8 编码来解码,如:
参见
知识库
相关问题
测试环境
操作系统版本:
Windows 7 Ultimate build 7600 |
浏览器版本:
IE6 IE7 IE8 Firefox 3.6.8 Chrome 6.0.495.0 dev Safari 5.0(7533.16) Opera 10.60 |
测试页面:
无 |
本文更新时间:
2010-08-20 |
关键字
URI URL ASCII 地址栏 中文 乱码 escape unescape encodeURI decodeURI
分享到:
相关推荐
- **创建和解析URI**:Uri库允许通过字符串或数组创建URI实例,并能解析出各个部分,如scheme(协议)、authority(授权部分,包括用户信息、主机和端口)、path(路径)、query(查询字符串)和fragment(片段...
uri转字符串路径,解决4.0以上的兼容问题,
### 三、URI中非ASCII字符的处理 在HTML4.01规范中提到,URI不应包含非ASCII字符。例如,以下链接是不合法的: ```html <a href="http://foo.org/Håkon"> ``` 对于这种情况,规范建议用户端采取一定的处理措施,...
下载编码的问题字符串转URI 在 JavaScript 中,字符串转化成 URI 的过程是必不可少的一步,对于 URI 中的特殊字符,需要进行编码,以便正确地传输和解析。在 JavaScript 中,有三个可以对字符串编码的函数,分别是 ...
3. **查询参数处理**:URI中可能包含查询字符串,这些字符串由键值对组成。URI-Fast应该能方便地解析和操作这些参数,支持添加、删除和修改。 4. **组件提取**:URI由多个部分组成,包括协议、主机名、端口、路径、...
它们都可以用于对字符串进行编码,但是它们之间有一些区别: * escape() 方法:采用 ISO Latin 字符集对指定的字符串进行编码。所有的空格符、标点符号、特殊字符以及其他非 ASCII 字符都将被转化成 %xx 格式的字符...
Ajax URI 乱码问题主要涉及浏览器差异和服务器配置两方面,尤其在处理非 ASCII 字符时,编码格式的不一致可能导致乱码。以下是对这个问题的详细解析和解决方案: 1. **浏览器差异**: - **Internet Explorer (IE)*...
标题 "中文转换成ASCII码并用十六进制表示 (转)" 涉及到的是字符编码转换的问题,主要关注的是如何将中文字符转换为ASCII码并以十六进制的形式展示。在计算机科学中,ASCII码是一种标准的字符编码,它只包含128个...
在Android开发中,嵌入浏览器功能通常通过使用WebView组件来实现。WebView是一个能够加载和显示网页的视图,允许开发者在应用程序内部呈现互联网内容。在本文中,我们将深入探讨如何在Android应用中使用WebView及其...
在Perl中,标准的URI编码库如`URI`或`URI::Escape`通常只处理ASCII字符集,而`URI::Escape::Any`扩展了这个功能,允许对Unicode字符进行更全面的编码。这意味着你可以用这个模块来处理包含非英文字符(如中文、日文...
在不同的上下文中,`Uri`可以有不同的含义,但在大多数情况下,它是用来表示一个文件的位置。 #### 获取真实路径的方法 下面我们将详细介绍如何编写一个方法来根据给定的`Uri`获取其对应的文件系统路径。 ```java...
`Addressable`库正是为了解决这个问题而诞生的,它是对Ruby内置`URI`库的一个增强版,特别是在处理国际化资源标识符(IRIs)和URI模板方面。 `Addressable`库遵循了三个重要的互联网标准:RFC 3986、RFC 3987和RFC ...
2. **浏览器兼容性**:虽然现代浏览器普遍支持dataURI和SVG,但老版本浏览器可能存在问题,需做好兼容性测试。 3. **缓存策略**:由于dataURI内容是内联的,不能利用浏览器的缓存机制,可能导致不必要的资源重复加载...
在C++程序中,与URI和URL相关的任务通常涉及字符串操作,而Boost.URL库则为这些任务提供了高级抽象,避免了底层的字符串处理复杂性。 Boost.URL库的核心功能包括: 1. **解析**: Boost.URL库可以将一个完整的URL...
在接收URL时,服务器或浏览器会自动对URL进行解码,将转义字符恢复为原始字符。开发者也可以使用编程语言提供的函数手动进行URL解码,例如JavaScript中的`decodeURI()`和`decodeURIComponent()`。 6. **URL编码与...
首先,浏览器的核心功能是接收用户输入的URI,向服务器发起请求,获取资源并显示在窗口中。资源通常以HTML格式为主,也可能包含图像、PDF等其他类型。W3C定义了HTML和CSS的规范,虽然各浏览器厂商有时会添加自己的...
Android Intent 的 URI 及示例 Android 操作系统中,Intent 是一个非常重要的组件,它允许不同的应用程序之间进行通信和交互。在 Android 中,Intent 是一个消息对象,它可以用来请求其他应用程序执行某些操作。...
在C#编程语言中,Base64是一种用于将二进制数据编码为ASCII字符串...在进行转换时,需要确保对字符串的编码有准确的理解,以便正确地转换和还原。在实际应用中,Base64编码对于二进制数据的传输和存储有着广泛的应用。
`android.intent.category.BROWSABLE`表示该Activity可以从浏览器或其他可以解析URI的应用启动。 一旦我们设置了scheme,外部应用就可以通过构造一个包含我们scheme的URI来启动我们的Activity。例如,一个可能的URI...
然而,需要注意的是,Data URI适合较小的文件,因为过大的文件可能会导致浏览器性能问题或达到URL长度限制。 #### 总结 Data URI提供了一种简单有效的方式来嵌入小文件到HTML或CSS中,有助于优化网站性能。通过...