URL编码
- URL编码,也称为百分号编码,是一种用于在URL(统一资源定位符)中传输特殊字符的编码方式
- 当 URL 路径或者查询参数中,带有中文或者特殊字符的时候,就需要对 URL 进行编码(采用十六进制编码格式)。URL 编码的原则是使用安全字符去表示那些不安全的字符
- 安全字符:指的是没有特殊用途或者特殊意义的字符
应用场景
- 浏览器地址栏:用户在输入含有特殊字符的URL时,浏览器会自动进行URL编码
- 表单数据提交:通过GET或POST方法提交表单时,数据中的特殊字符会被编码,以确保传输的正确性
- API请求:在RESTful API中,URL编码用于传递参数,确保参数值中包含的特殊字符不会破坏URL结构
- 文件传输:在文件名中包含特殊字符时,URL编码用于正确传输文件路径。
URL结构分解
- URL 中规定了一些具有特殊意义的字符,常被用来分隔两个不同的 URL 组件,这些字符被称为保留字符
- 冒号:用于分隔协议和主机组件,斜杠用于分隔主机和路径
- ?:用于分隔路径和查询参数等
- =:用于表示查询参数中的键值对
- &:用于分隔查询多个键值对
- 其余常用的保留字符有:/ . … # @ $ + ; %
http://example.com:8080/path/to/index.php?param1=value1¶m2=value2#section
- 协议:http://(或https://)
- 域名:example.com
- 端口::8080(默认HTTP端口80、HTTPS端口443可省略)
- 路径:/path/to/index.php(服务器上的文件路径)
- 查询参数(查询字符串):?param1=value1¶m2=value2
- 片段标识:#section(页面内锚点)
编码原理
- 使用百分号(%)后跟随两个十六进制数字来表示该字符的ASCII码。通过这种方式,任何字符都可以被安全地包含在URL中
编码规则
- 保留字符编码:将所有保留字符转换为其ASCII码对应的百分号编码。例如,空格(
)的ASCII码是32,对应的十六进制是20,因此空格在URL中表示为%20
- 非ASCII字符编码:对于URL中包含的非ASCII字符(如中文字符),首先将其转换为UTF-8编码的字节序列,然后将每个字节转换为百分号编码。例如,中文字符“你”的UTF-8编码为
E4 BD A0
,对应的URL编码为%E4%BD%A0
- 非保留字符不编码:非保留字符可以直接使用,不需要进行编码
哪些字符需要编码
- URL 之所以需要编码,是因为 URL 中的某些字符会引起歧义,比如 URL 查询参数中包含了”&”或者”%”就会造成服务器解析错误
- URL 的编码格式采用的是 ASCII 码而非 Unicode 格式,这表明 URL 中不允许包含任何非 ASCII 字符(比如中文),否则就会造成 URL 解析错误。
- URL 编码协议规定(RFC3986 协议):URL 中只允许使用 ASCII 字符集可以显示的字符(安全字符/非保留字符)
- 英文字母、数字、和
-
_
.
~
这 6 个特殊字符
- 当在 URL 中使用不属于 ASCII 字符集的字符时,就要使用特殊的符号对该字符进行编码,比如空格需要用%20来表示
- 除了无法显示的字符需要编码外,还需要对 URL 中的部分保留字符和不安全字符进行编码
- 示例:!, *, ', (, ), ;, :, @, &, =, +, $, ,, /, ?, #, [, ], <, >, ", ", {, }, |, , ^等
URL特殊字符编码
字符 |
含义 |
十六进制值编码 |
+ |
URL 中 + 号表示空格 |
%2B |
空格 |
URL中的空格可以编码为 + 号或者 %20 |
%20 |
/ |
分隔目录和子目录 |
%2F |
? |
分隔实际的 URL 和参数 |
%3F |
% |
指定特殊字符 |
%25 |
# |
表示书签 |
%23 |
& |
URL 中指定的参数间的分隔符 |
%26 |
= |
URL 中指定参数的值 |
%3D |
Python实现编码与解码
- Python 的标准库urllib.parse模块中提供了用来编码和解码的方法,分别是 urlencode() 与 unquote() 方法。
urlencode()
:该方法实现了对 url 地址的编码操作
quote()
:该方法实现了对 url 地址的编码操作
unquote()
:该方法将编码后的 url 地址进行还原,被称为解码
- 注意:quote() 只能对字符串编码,而 urlencode() 可以直接对查询字符串字典进行编码
#导入parse模块
from urllib import parse
#构建查询字符串字典
query_string = {
'wd' : '爬虫'
}
#调用parse模块的urlencode()进行编码
result = parse.urlencode(query_string)
#使用format函数格式化字符串,拼接url地址
url = 'http://www.baidu.com/s?{}'.format(result)
print(url)#注意url的书写格式,和 urlencode存在不同
url = 'http://www.baidu.com/s?wd={}'
word = input('请输入要搜索的内容:')
#quote()只能对字符串进行编码
query_string = parse.quote(word)
print(url.format(query_string))urllib.parse.urlencode({'key':'value'}) #字典
urllib.parse.quote(string) #字符串string = '%E7%88%AC%E8%99%AB'
result = parse.unquote(string)
print(result)
URL解码
浏览器解码逻辑详解
- 自动解码的触发条件:
- 仅对合法编码序列解码:若输入形如%XX(X为十六进制字符),浏览器会尝试解码。
- 非编码字符保留原样:例如%zz(非法编码)会被直接发送。
- 双重编码的递归解码:
- 浏览器仅解码一次:不会递归解码多次。
- 输入%2525 → 解码为%25,不会继续解码为%。
- 安全字符的特殊处理
- 部分浏览器优化:对某些安全字符(如字母)的编码可能自动解码
- 输入%41 → 发送时可能直接转为A
- 利用:
浏览器解码策略
浏览器 |
双重编码处理 |
安全字符编码处理 |
Chrome |
解码一次(发送单层编码) |
可能自动解码为明文 |
Firefox |
解码一次(发送单层编码) |
保留编码形式 |
Safari |
同Chrome |
同Chrome |
Edge |
同Chrome |
同Chrome |
