URL(URI) 中的编码与乱码(上)--路径(path)中的编码

news/2024/7/3 12:29:42 标签: 字符集, 编码, 乱码, URL, URI, 路径

在之前说完了静态 html 页面的中的编码(一, 二, 三, 四, 五 ), 接着又谈论了动态 html 页面中的编码问题, 具体以 java 平台为例, 谈论了 servlet 中的编码乱码问题 以及 jsp 中的编码乱码问题.

虽然没有涉及更多的语言平台, 比如 php, asp, 乃至 nodejs, python, ruby 等, 但背后的原理基本也是相通的.

这一次将转入一个新的话题, 就是 URL 中的编码乱码问题.

URL_6">带有中文的 URL

我们依然从一些简单的实验开始去探讨, 而不是直接给出一些结论. 先创建两个有着中文文件名的 html, 页面编码分别是 utf-8 和 gbk;以及一个中文名的文件夹, 下面再放一个普通的 html 文件, 如下所示:

中文 url 文件名 <a class=路径名" />

自然, 你可能听说过很多前辈们的警告: 千万别用中文作文件名或路径名(文件夹名). 这种警告应该说是中肯的, 但也不意味着用了中文就一定有问题.

前面三个文件的内容如下:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>位于中文文件夹下的文件</title>
</head>
<body>在【你好】 文件夹下的 index.html
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="GBK">
<title>带中文的 URL(GBK)</title>
</head>
<body>
	测试带中文的 URL,页面编码为:GBK
	<br> 中文链接:
	<a href="你好/index.html">你好/index.html</a>
	<br> 中文链接并带有中文查询字符串:
	<a href="你好/index.html?s=你好">你好/index.html?s=你好</a>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>带中文的 URL(UTF-8)</title>
</head>
<body>
	测试带中文的 URL,页面编码为:UTF-8
	<br> 中文链接:
	<a href="你好/index.html">你好/index.html</a>
	<br> 中文链接并带有中文查询字符串:
	<a href="你好/index.html?s=你好">你好/index.html?s=你好</a>
</body>
</html>

在前面两个文件中还使用了一个 a 标签的超链接, href 中的内容也是包含有中文的:

<a href="你好/index.html">

有的还带有中文的查询字符串:

<a href="你好/index.html?s=你好">

把以上部署到 tomcat8 中, 然后在 chrome 中访问【主页utf8.html】 文件:

浏览器 中文 url  访问

首先, 打开是没有问题的, 地址栏的链接也是中文, 不过地址栏这里浏览器为了对用户友好, 实际上使用了一点障眼法. 如果你把地址栏的内容拷贝出来, 粘贴到一个文本文件上, 会发现实质的内容是这样的:

中文 url  转义表示

又或者你打开"开发者工具", 在其中的请求头标签页下查看:

中文 url  请求头转义表示

会发现【主页】两个汉字被取代了, 真正的内容是 “%E4%B8%BB%E9%A1%B5” 这样一串字符.

URL__88">URL 中的转义表示

那么, 像这样的一串字符 “%E4%B8%BB%E9%A1%B5”, 其中的每一个部分用【%XX】来表示, 其中 XX 表示一个十六进制的数(hexadecimal digits), 这样的表示就是所谓的 URL 的转义表示, 也叫 百分号编码(Percent-Encoding).

如果把其中的百分号 % 去掉, 会发现结果是"E4 B8 BB E9 A1 B5", 总共 6 个字节, 其实就是"主页"两字的 utf-8 编码.

如果你还记得先前说到的 utf-8 的编码模式, EX XX XX 通常就是常用汉字的模式.

那么现在比较清楚了, URL 路径中的中文需要转义, 具体编码用的是 utf-8.

URL__98">为什么 URL 中中文需要转义

你可能会想, 为什么 URL 中的中文要转义呢? 转成那样一串东西, 猛看上去也不知道它到底代表什么汉字, 怪怪的. 那么这个原因简单讲就是 URL 中的规范就是这么规定的.

更准确地说是 URI 规范. URLURI 的一种, 常见的 URI 通常也都是 URL, 一般情况下会混着用两者.

关于 URI 规范, 具体可见 http://www.ietf.org/rfc/rfc2396.txt 和 http://www.ietf.org/rfc/rfc3986.txt. (后面的为更新的规范)

URI__106">URI 规范中对于转义的规定

考虑到 URI 在各种平台间传输时的兼容性, URI 规范中规定只有 US-ASCII 字符集中的字符可以直接出现在 URI 中. 事实上, 甚至 ASCII 本身的许多字符也不允许直接出现在 URI 中, 有的也要转义.

可以直接用的有 26 个大小写字母, 10 个数字, 还有以下四个标点符号:

  • “-”, 短横(中划线)
  • “.”, 点号
  • “_”, 下划线
  • “~”, 波浪线

其它的有的属于 保留字, 用作为 分隔符(delimiters), 它们有:

  • “:”, 冒号
  • “/”, 正斜杠
  • “?”, 问号
  • “#”, 井号
  • “[”, 左中括号
  • “]”, 右中括号
  • “@”, 地址符号
  • “!”, 感叹号
  • “$”, 美元符号
  • “&”, 与
  • “'”, 单引号
  • “(”, 左小括号
  • “)”, 右小括号
  • “*”, 星号
  • “+”, 加号
  • “,”, 逗号
  • “;”, 分号
  • “=”, 等号

比如正斜杠 “/” 就是一个最常用的分隔符. 如果想在 URL 中包含这样符号, 又不想它们被解析为分隔符, 就要对其转义.

分隔符还具体分为 通用分隔符子部件分隔符, 具体什么时候需要转义的细节参见上述提到的规范.

其它的还有一些不可以打印的字符也要转义, 比如"空格"等.

所以, URI 中可用的字符实际是比较有限的, 最好只使用那些安全的字符, 就是 26 个字母加数字.

如果用了其它, 就免不了要转义, 然后各种编码, 解码, 通过各种网关, 代理, 各种转发过程时等也容易发生错误.

URL__146">浏览器对中文路径 URL 的转义

比如上面说到的中文, 那就要转义, 虽然在 href 中直接写的是中文, 但正规的浏览器都会对其先转义然后才发送请求.

比如, 在上述页面中, 继续点击其中的链接"你好/index.html":

浏览器访问中文 url <a class=路径" />

就进入了那个中文文件夹路径下, 具体查看一下请求, 发现也是转义了的:

中文 url <a class=路径 请求头 转义表示" />

虽然在 href 中是直接写的中文, 但浏览器悄悄地做了转义.

当然你也可以自己先行转义好放在 href 那, 具体请参考 urlEncode 等方法, 这样浏览器就不会再转了.

URIEncoding__162">tomcat 与 URIEncoding 设置

另一方面, 除了浏览器这边的转义外, server 端也要能正确地解码. 其实这里把它部署到 tomcat8 中, 没有出现问题, 但假如是部署到 tomcat7 中, 再请求时会发现 404 错误, 找不到文件了:

tomcat6 tomcat7 中文 url 找不到文件 404

请求的 url 还是一样的, 也是转义的了, 但是问题出在 tomcat7 接受到这个转义 url 的处理上, 原来它默认是按 iso-8859-1 来解码的, 导致无法正确地得到 “主页utf8.html”, 因此就出错了.

为此, 还要去到 server 的配置文件目录下, 找到 server.xml:

tomcat server.xml

再在 server.xml 文件中找到端口为 8080 的那个 Connector, 增加一个设置 URIEncoding="UTF-8", 这样之后才能正常:

也即这样:

<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" URIEncoding="UTF-8"/>

那为什么 tomcat8 又 OK 呢? 原来从 8 开始(具体为 8.0.0-RC3), 这个默认值改为了 utf-8, 于是就不用你自己去设置了. 具体见: https://wiki.apache.org/tomcat/FAQ/CharacterEncoding#Q2

其实严格地讲, 还会受一个叫 “strict servlet compliance” 的设置的影响, 这个设置默认是 off, 这时的值就是 utf-8;

而假如为 on 的话, 表明严格地遵循 servlet 规范, 此时即便在 tomcat8 下也是 iso-8859-1, 那么就也要手动配置这个值.

如果你用的不是 tomcat, 那么你要自行查阅资料了解缺省值的配置.

由于篇幅关系, 涉及到 gbk 页面下的测试及查询字符串相关的一些情况留待下篇再分析.


http://www.niftyadmin.cn/n/1005725.html

相关文章

springboot 项目里面使用nacos ,不需要配置nacos 的用户名密码嘛

目录 1 解决 1 解决 当在Spring Boot项目中使用Nacos时&#xff0c;如果您不需要配置Nacos的用户名和密码&#xff0c;可以将username和password属性留空或不配置。这样&#xff0c;Nacos客户端将以匿名方式连接到Nacos服务器。 在bootstrap.yml或application.yml中配置Nacos…

【Android从零单排系列三十三】《Android布局介绍——FrameLayout》

目录 前言 一 FrameLayout基本介绍 二 FrameLayout使用方法 三 FrameLayout常见属性及方法 四 FrameLayout简单案例 五 总结 前言 小伙伴们&#xff0c;在上文中我们介绍了Android布局AbsoluteLayout&#xff0c;本文我们继续盘点介绍Android开发中另一个常见的布局&…

NLP学习笔记(三)

一&#xff1a;分类方法 &#xff08;一&#xff09;逻辑回归 最简单的方法就是将分类问题视为回归问题&#xff0c;采用逻辑回归计算分类的边界。 &#xff08;二&#xff09;softmax回归 softmax的前向传播过程可以分为以下三步&#xff1a; h W T x y ^ s o f t m a …

nvme ssd挂载

内置 f2进入biossystem configuration下将sata operation右侧设置为AHCIboost sequence中右侧boot list option改为UEFI后续进行磁盘挂载 #查看新添加的盘符 fdisk -l #格式化硬盘文件系统 mkfs -t ext4 /dev/nvme #挂载硬盘 mkdir /nvme mount /dev/nvme /nvme #查看UUID su…

Android Audio - AAudio框架

参考文献&#xff1a; Android AAudio 的实现分析_hanpfei的博客-CSDN博客 Android AAudio详解 - 简书 Android R音频输出问题处理随笔_audiodevicebroker_嘴巴吃糖了的博客-CSDN博客

登录远程Linux桌面

远程桌面连接主要使用两种协议&#xff0c;一种是Windows上RDP协议&#xff0c;第二种是VNC协议&#xff0c;从使用效果来看&#xff0c;vnc更优秀。 一、VNC 使用x11vnc 1.安装x11vnc sudo apt install x11vnc 2.启动x11vnc x11vnc -passwd orangepi -display :0 -forever…

前端知识学习

以下是一个使用Angular 13实现的示例代码&#xff0c;实现了当div出现滚动条时给div底部加上阴影效果&#xff0c;并随着滚动条的拖动保留阴影效果&#xff0c;当滚动条拉到最后时&#xff0c;阴影效果消失。 首先&#xff0c;在你的组件的HTML模板中添加以下代码&#xff1a;…