什么是 URL 编码?

URL 编码(也称为百分号编码)是一种将字符转换为可在 URL 中安全传输的格式的机制。由于 URL 只能包含 ASCII 字符集中的特定字符,其他字符(如中文、空格、特殊符号)必须被编码为 % 后跟两位十六进制数的形式。

URL 编码确保了 URL 在不同系统和浏览器之间能够正确传输和解析,是 Web 开发中不可或缺的基础知识。

需要编码的字符

保留字符(必须编码)

: %3A/ %2F? %3F# %23[ %5B] %5D@ %40! %21$ %24& %26' %27( %28) %29* %2A+ %2B, %2C; %3B= %3D% %25空格 %20

中文字符示例

%E4%BD%A0%E5%A5%BD%E4%B8%96%E7%95%8C

URL 编码示例

原始文本
Hello World
Hello%20World
原始文本
你好世界
%E4%BD%A0%E5%A5%BD%E4%B8%96%E7%95%8C
原始文本
a=1&b=2
a%3D1%26b%3D2
原始文本
https://example.com/path?query=test
https%3A%2F%2Fexample.com%2Fpath%3Fquery%3Dtest

编程语言中使用 URL 编码

JavaScript

// 编码完整 URL
const encoded = encodeURIComponent('你好世界');
console.log(encoded); // "%E4%BD%A0%E5%A5%BD%E4%B8%96%E7%95%8C"

// 解码
const decoded = decodeURIComponent('%E4%BD%A0%E5%A5%BD%E4%B8%96%E7%95%8C');
console.log(decoded); // "你好世界"

// 编码完整 URL(保留协议等)
const url = encodeURI('https://example.com/路径?查询=测试');
console.log(url); // "https://example.com/%E8%B7%AF%E5%BE%84?%E6%9F%A5%E8%AF%A2=%E6%B5%8B%E8%AF%95"

Python

from urllib.parse import quote, unquote, urlencode

# 编码
encoded = quote('你好世界')
print(encoded)  # "%E4%BD%A0%E5%A5%BD%E4%B8%96%E7%95%8C"

# 解码
decoded = unquote('%E4%BD%A0%E5%A5%BD%E4%B8%96%E7%95%8C')
print(decoded)  # "你好世界"

# 编码查询参数
params = {'name': '张三', 'age': 25}
query = urlencode(params)
print(query)  # "name=%E5%BC%A0%E4%B8%89&age=25"

Java

import java.net.URLEncoder;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;

// 编码
String encoded = URLEncoder.encode("你好世界", StandardCharsets.UTF_8);
System.out.println(encoded); // "%E4%BD%A0%E5%A5%BD%E4%B8%96%E7%95%8C"

// 解码
String decoded = URLDecoder.decode("%E4%BD%A0%E5%A5%BD%E4%B8%96%E7%95%8C", StandardCharsets.UTF_8);
System.out.println(decoded); // "你好世界"

PHP

// 编码
$encoded = urlencode('你好世界');
echo $encoded; // "%E4%BD%A0%E5%A5%BD%E4%B8%96%E7%95%8C"

// 解码
$decoded = urldecode('%E4%BD%A0%E5%A5%BD%E4%B8%96%E7%95%8C');
echo $decoded; // "你好世界"

// 编码完整 URL
$encoded = rawurlencode('你好世界');
echo $encoded; // "%E4%BD%A0%E5%A5%BD%E4%B8%96%E7%95%8C"

Go

import "net/url"

// 编码
encoded := url.QueryEscape("你好世界")
fmt.Println(encoded) // "%E4%BD%A0%E5%A5%BD%E4%B8%96%E7%95%8C"

// 解码
decoded, _ := url.QueryUnescape("%E4%BD%A0%E5%A5%BD%E4%B8%96%E7%95%8C")
fmt.Println(decoded) // "你好世界"

// 编码 URL 参数
params := url.Values{}
params.Add("name", "张三")
fmt.Println(params.Encode()) // "name=%E5%BC%A0%E4%B8%89"

C#

using System.Web;

// 编码
string encoded = HttpUtility.UrlEncode("你好世界");
Console.WriteLine(encoded); // "%e4%bd%a0%e5%a5%bd%e4%b8%96%e7%95%8c"

// 解码
string decoded = HttpUtility.UrlDecode("%E4%BD%A0%E5%A5%BD%E4%B8%96%E7%95%8C");
Console.WriteLine(decoded); // "你好世界"

// .NET Core 推荐
encoded = Uri.EscapeDataString("你好世界");
decoded = Uri.UnescapeDataString("%E4%BD%A0%E5%A5%BD%E4%B8%96%E7%95%8C");

Ruby

require 'uri'

# 编码
encoded = URI.encode_www_form_component('你好世界')
puts encoded # "%E4%BD%A0%E5%A5%BD%E4%B8%96%E7%95%8C"

# 解码
decoded = URI.decode_www_form_component('%E4%BD%A0%E5%A5%BD%E4%B8%96%E7%95%8C')
puts decoded # "你好世界"

# 编码查询参数
params = { name: '张三', age: 25 }
query = URI.encode_www_form(params)
puts query # "name=%E5%BC%A0%E4%B8%89&age=25"

Shell / 命令行

# 编码(需要 python 或 jq)
python3 -c "import urllib.parse; print(urllib.parse.quote('你好世界'))"
# 输出: %E4%BD%A0%E5%A5%BD%E4%B8%96%E7%95%8C

# 使用 jq
echo -n '你好世界' | jq -sRr @uri
# 输出: %E4%BD%A0%E5%A5%BD%E4%B8%96%E7%95%8C

# 解码
python3 -c "import urllib.parse; print(urllib.parse.unquote('%E4%BD%A0%E5%A5%BD%E4%B8%96%E7%95%8C'))"
# 输出: 你好世界

encodeURI vs encodeURIComponent

方法用途不编码的字符
encodeURI编码完整 URL: / ? # [ ] @ ! $ & ' ( ) * + , ; =
encodeURIComponent编码 URL 参数值- _ . ! ~ * ' ( )
encodeURI:用于编码完整的 URL,保留 URL 结构字符(如 ://、?、& 等)
encodeURIComponent:用于编码 URL 参数值,会编码所有特殊字符

URL 编码常见应用场景

🔗 URL 参数传递

在 GET 请求中传递包含特殊字符的参数值

🌐 中文 URL

处理包含中文字符的 URL 路径和参数

📤 表单提交

application/x-www-form-urlencoded 格式的数据编码

🔐 OAuth 认证

OAuth 回调 URL 和状态参数的编码

📱 API 调用

RESTful API 请求参数的编码处理

📧 邮件链接

mailto 链接中主题和内容的编码

常见问题

Q: URL 编码和 Base64 编码有什么区别?

A: URL 编码是将特殊字符转换为 %XX 格式,用于确保 URL 的正确传输;Base64 是将二进制数据转换为 ASCII 字符串,用于在文本协议中传输二进制数据。两者用途不同,不能互相替代。

Q: 空格应该编码为 %20 还是 +?

A: 在 URL 路径中,空格应编码为 %20;在 application/x-www-form-urlencoded 格式(如表单提交、查询字符串)中,空格可以编码为 +。现代实践中推荐统一使用 %20。

Q: 为什么有时候 URL 中的中文不编码也能访问?

A: 现代浏览器会自动对 URL 中的非 ASCII 字符进行编码显示,但实际传输时仍会进行编码。为了兼容性和正确性,建议在代码中显式进行 URL 编码。

Q: URL 编码后长度会增加多少?

A: 每个 ASCII 字符编码后仍为 1 个字符,每个非 ASCII 字符(如中文)编码后变为 9 个字符(3 个 %XX 格式)。例如,一个中文字符编码后变为 %XX%XX%XX 共 9 个字符。