url编码的“完全双向”指encode/decode能精确还原任意std::string字节序列(含空字节、非法utf-8等),需逐字节十六进制编码、严格校验%xx解码并拒绝非法输入。

什么是URL编码的“完全双向”?
所谓完全双向,是指 encode 后的字符串能被 decode 精确还原为原始字节序列(而非仅还原为原始字符串),且对任意 std::string(含空字节、控制字符、非UTF-8字节序列)都成立。C++标准库不提供此能力——std::urlencode 不存在,而 std::regex 或 std::string_view 手动处理容易漏掉 '%' 转义冲突或越界解码。
如何安全实现 encode:逐字节转十六进制 + 百分号转义
URL编码本质是字节级操作,不是字符级。必须避免先用 .c_str() 再调用 C 函数(会截断空字节),也不能依赖 locale 或 UTF-8 解码逻辑(原始字符串可能根本不是合法 UTF-8)。
- 遍历
std::string的每个unsigned char,跳过A-Z、a-z、0-9、'-'、'_'、'.'、'~'(RFC 3986 安全字符) - 其余字节统一格式化为
"%XX",其中XX是该字节的两位大写十六进制表示(如0x20→"%20") - 特别注意:空字节
\0必须编码为"%00",否则后续c_str()或strlen类操作会提前截断
std::string url_encode(const std::string& s) {
std::string out;
out.reserve(s.size() * 3); // 最坏情况:全编码,每字节变3字符
for (unsigned char c : s) {
if ((c >= 'A' && c = 'a' && c = '0' && c > 4];
out += "0123456789ABCDEF"[c & 0xF];
}
}
return out;
}
如何可靠实现 decode:严格匹配 %XX 模式 + 拒绝非法输入
url_decode 是更易出错的一端。常见坑包括:"%G0" 这类非法十六进制、"%FF%" 结尾不完整、"%00" 解码后引入空字节导致后续 string 操作异常。必须拒绝所有非法输入,不能静默忽略。
- 扫描字符串,遇到
'%'就检查后续两个字符是否均为十六进制数字(0-9、A-F、a-f) - 若任一字符非法,直接返回空
std::string或抛出异常(推荐后者) - 解码结果直接 push_back 到
std::string—— 它天然支持空字节和任意二进制数据 - 不要用
std::stoi(str, nullptr, 16),它对单字节"FF"可能溢出或接受前导空格;应手动查表或用std::from_chars(C++17)
std::string url_decode(const std::string& s) {
std::string out;
out.reserve(s.size()); // 解码后长度 ≤ 原长
for (size_t i = 0; i = '0' && hex1 = 'A' && hex1 = 'a' && hex1 = '0' && hex2 = 'A' && hex2 = 'a' && hex2 ((hi <h3>为什么不能直接用第三方库(如 Boost.URL)?</h3><p>Boost.URL 的 <code>boost::urls::encode</code> 和 <code>boost::urls::decode</code> 默认按 UTF-8 字符处理,且 decode 会将 <code>"%00"</code> 视为错误并返回失败状态 —— 它设计目标是 URI 组件解析,不是通用二进制编码容器。若你传入含 <code>\0</code> 或乱码字节的 <code>std::string</code>,它要么拒绝,要么静默损坏数据。真正需要“完全双向”的场景(如加密 token 序列化、二进制 payload URL 传输),必须自己控制字节流边界。</p><p>最常被忽略的是:URL 编码/解码不是文本编解码,它是传输层的字节转义机制。任何试图先转换成 <code>std::u8string</code> 或调用 <code>std::codecvt_utf8</code> 的做法,都会在非 UTF-8 输入上崩溃或产生未定义行为。</p>C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











