进制君在线工具合集

16进制url编码:百分号后面为什么总跟着数字和字母

浏览网页时,地址栏里偶尔会冒出一串以百分号开头的字符,比如把空格变成 %20,把中文变成一长串 %E4%B8%AD 之类的东西。这就是常说的16进制url编码。它解决的是「URL 只能安全携带一部分字符」的问题:把不能直接出现的字符,按字节换算成十六进制,再在前面加百分号。读者通常关心三件事——它到底怎么算出来的、什么时候会遇到、以及看到或需要构造这种字符串时该注意什么。

先弄清它到底在编码什么

很多人以为16进制url编码是把字符直接换成十六进制数字,其实中间还隔着一层字节。以常见的 UTF-8 为例,一个汉字在内存里占多个字节,编码时先把这些字节逐个取出,每个字节写成两位十六进制,再各自加上百分号。所以你会看到连续好几个百分号拼在一起,它们合起来才代表一个字符。

这也解释了一个常见误会:同一个汉字在不同字符集下的编码结果不一样。早期网页用 GBK,如今大多用 UTF-8,同一段文字转出来的百分号串长度和内容都可能不同。排查乱码时,先确认编码所用的字符集,比盯着那串数字本身更有用。

哪些字符会被转,哪些可以留着

URL 有一套保留字符的约定,比如斜杠、问号、井号、与号,它们在地址里有语法作用,不能随意当普通文本使用。如果参数值里本身就含有这类字符,就必须转义,否则解析时会提前截断或改变含义。

另一类是所谓不安全字符,最典型的是空格。空格在地址里无法直接出现,于是被写成 %20;在查询串里也常见用加号代替空格的做法,两种写法来源不同,处理时别混为一谈。字母、数字和少数标点通常保持原样,因为它们是安全的。判断某个字符要不要转,看它在当前上下文里是否可能引起歧义,而不是死记一张表。

实际遇到它的几个场景

做接口联调时,参数里带中文或特殊符号,对方收到的却是百分号串,这往往不是出错,而是传输前的正常转义。抓包工具里看到的请求行、日志里记录的访问地址,也常以这种形式呈现,直接肉眼读会很痛苦,需要先还原再分析。

还有一类场景是拼接跳转地址。把一个带查询参数的链接塞进另一个链接的参数里,如果不转义,内层的与号和问号会和外层的混在一起,服务端解析出来的参数就乱了。此时对整段内层地址做一次编码,是常见做法。反过来的坑也存在:对已经编码过的字符串再编码一次,百分号本身被转成 %25,结果多出一层,排查起来很费时间。

手动处理时的几个提醒

第一,编码和解码要成对出现,且只做一次。看到 %25 就要意识到它可能代表一个百分号,而不是又一个转义的开头。

第二,别用字符串替换的方式去处理中文。有人图省事,把几个常见汉字硬编码成对应串,遇到新字就失效。正确的思路是按字节处理,让程序完成字符集到字节的转换。

第三,注意大小写。十六进制里的字母大小写不影响含义,但比较字符串时可能造成不一致,做去重或缓存键时最好统一。

第四,路径段和查询参数对某些字符的宽容度不同,同一个字符在不同位置是否需要转义,答案未必一样。拿不准时,宁可交给标准库函数处理,也不要凭感觉手写。

总结

16进制url编码的本质是按字节转十六进制并加百分号,用来让地址安全携带特殊字符。理解字符集这一层,能解释中文变长串和结果不一致的现象;使用时注意只编一次、成对解码、交给标准库处理,比死记字符表更可靠。

相关文章

常见问题

Q1为什么中文会变成一长串百分号?

因为一个汉字在 UTF-8 下占多个字节,每个字节都要单独转成两位十六进制并加百分号,所以看起来很长。这串字符合起来才对应一个汉字,不能拆开理解。

Q2空格写成加号和写成百分号加数字有区别吗?

来源不同。加号代替空格多见于表单提交的查询串,百分号形式则是通用的转义写法。两者在部分解析器里可以互通,但并非所有场合都等价,处理时按实际协议约定来。

Q3同一段文字编码结果为什么和别人不一样?

多半是字符集不同。UTF-8 与 GBK 对同一汉字的字节表示不一样,转出来的十六进制自然不同。先统一字符集,再比较结果。

Q4看到 %25 应该怎么理解?

%25 是百分号本身的转义形式。如果原字符串里本来就有百分号,编码后就会出现它。这也提示你,可能发生了重复编码。