URL编码是RFC 3986强制要求的百分号编码机制,仅大小写字母、数字及-._~共72个字符无需编码,其余字节(如空格→%20、UTF-8中文→%E4%BD%A0%E5%A5%BD)必须转义为%XX形式。

组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
什么是URL编码,哪些字符必须被编码
URL编码(Percent Encoding)不是可选的美化操作,而是RFC 3986强制要求:所有不在unreserved字符集中的字节,都必须转义为%XX形式。这个集合只有大小写字母、数字和-._~共72个字符。空格必须变成%20,中文如你好(UTF-8下是E4 BD A0 E5 A5 BD)就得变成%E4%BD%A0%E5%A5%BD。别用std::isalnum简单判断——它不认~,也不处理多字节UTF-8;直接按字节检查更可靠。
C++中手写encode函数的关键细节
标准库不提供URL编码,得自己写。核心是逐字节检查+查表转换:
– 遍历输入字符串每个unsigned char(避免符号扩展)
– 对每个字节,查预定义的布尔数组should_encode[256]:true表示需编码
– 若需编码,用std::sprintf(buf, "%%%.2X", byte)写入(注意%%转义)
– 否则直接追加原字符
– 不要试图“先转UTF-8再编码”:输入字符串若已是UTF-8(如std::string),就直接按字节处理;若传入std::wstring,得先调用std::wstring_convert或C++11后用std::codecvt_utf8转码,但容易出错,建议接口统一收std::string并假设为UTF-8
bool should_encode[256] = {};
// 初始化:全设false,再把非unreserved设true
for (int i = 0; i < 256; ++i) {
should_encode[i] = true;
}
for (char c = 'A'; c <= 'Z'; ++c) should_encode[(unsigned char)c] = false;
for (char c = 'a'; c <= 'z'; ++c) should_encode[(unsigned char)c] = false;
for (char c = '0'; c <= '9'; ++c) should_encode[(unsigned char)c] = false;
for (char c : "-._~") should_encode[(unsigned char)c] = false;
decode时如何安全处理%XX序列
解码比编码更容易出错:无效序列如%GH、%2、%结尾,必须拒绝而非静默忽略。
– 用std::istringstream或std::stoi(s, nullptr, 16)解析两位十六进制数,捕获异常或检查返回值
– 遇到%但后续不足两位,或字符非法(如G),应停止并返回std::nullopt或抛异常
– 不要盲目调用std::tolower:%AB和%ab都合法,但%Ab混合大小写也合法,直接用std::isxdigit判字符,再用std::isdigit/std::isalpha分别转数值
– 解码结果仍是字节流,不自动转码:若原始是UTF-8编码的中文,解码后还是UTF-8字节,应用层需自行处理显示逻辑
常见坑:空格、+号、路径分隔符的特殊处理
Web表单提交时,空格常被编码为+而非%20,这是application/x-www-form-urlencoded的约定,和通用URL编码不同。你的函数是否支持+→空格,取决于使用场景:
– 如果只处理URI path/query(如https://ex.com/q?k=v),严格按RFC,只认%20,忽略+
– 如果解析表单POST body,则必须额外处理+→' ',且仅在value部分(key里一般不用)
– /、?、=等在URL中有语法意义,是否编码取决于上下文:path段里的/通常不编码(表示层级),但作为参数值出现时(如file=/home/a.txt)就必须编码为%2F
– 别用std::replace全局替换+:可能误伤URL里本意就是加号的内容(比如数学API:/calc?expr=1%2B2)
?、=也干掉,导致URL结构损坏。

















