如何调用Windows原生API实现form-urlencoded格式URL编码
Windows 原生API实现form-urlencoded格式URL编码
验证基准
- 待编码原始字符串:
Polo Perú Qatar 2022 - Mujer - Colección Fútbol - 符合要求的编码结果:
Polo+Per%C3%BA+Qatar+2022+-+Mujer+-+Colecci%C3%B3n+F%C3%BAtbol
该编码属于application/x-www-form-urlencoded规范,核心特征为空格替换为+,非ASCII字符按UTF-8编码后做百分号转义,和RFC 3986标准URL编码(空格转义为%20)存在细微差异。
可直接调用的原生API方案
以下所有函数均为Windows系统自带、公开文档支持的可直接调用API,无需依赖任何第三方库,和MessageBox、GetSystemMetrics等常见系统函数属于同一类原生实现。
方案1:WinINet 组件 InternetCanonicalizeUrlW(全Windows版本兼容,从Windows 2000/IE4开始支持)
这个是最贴合需求的原生函数,不需要额外做字符串替换,直接通过flag控制输出格式:
- 头文件:
wininet.h - 链接依赖:
wininet.lib(系统SDK自带) - 核心标志位:
ICU_ENCODE_SPACES_AS_PLUS:将空格直接替换为+,匹配form编码要求ICU_ESCAPE_UNSAFE:对所有非安全字符、非ASCII字符按UTF-8编码做百分号转义
- 调用示例代码:
#include <windows.h> #include <wininet.h> #pragma comment(lib, "wininet.lib") #include <string> std::string UrlEncodeForm(const std::string& utf8Input) { // 入参转宽字符适配Unicode版本API int wLen = MultiByteToWideChar(CP_UTF8, 0, utf8Input.c_str(), -1, nullptr, 0); wchar_t* wBuf = new wchar_t[wLen]; MultiByteToWideChar(CP_UTF8, 0, utf8Input.c_str(), -1, wBuf, wLen); DWORD outLen = INTERNET_MAX_URL_LENGTH; wchar_t* wOut = new wchar_t[outLen]; std::string res; if (InternetCanonicalizeUrlW(wBuf, wOut, &outLen, ICU_ENCODE_SPACES_AS_PLUS | ICU_ESCAPE_UNSAFE)) { // 结果转回UTF-8输出 int utf8Len = WideCharToMultiByte(CP_UTF8, 0, wOut, -1, nullptr, 0, nullptr, nullptr); char* utf8Buf = new char[utf8Len]; WideCharToMultiByte(CP_UTF8, 0, wOut, -1, utf8Buf, utf8Len, nullptr, nullptr); res = utf8Buf; delete[] utf8Buf; } delete[] wBuf; delete[] wOut; return res; }
传入测试字符串调用该函数,输出结果和要求的预期完全一致。
方案2:Shlwapi 组件 UrlEscape(Win7及以上版本支持)
如果不想依赖WinINet组件,可以使用shlwapi.dll导出的UrlEscape函数,该函数原生支持UTF-8编码输出,只需要在编码完成后将结果中所有%20替换为+即可,同样是系统原生实现:
- 头文件:
shlwapi.h - 链接依赖:
shlwapi.lib - 核心标志位:
URL_ESCAPE_AS_UTF8:非ASCII字符按UTF-8编码转义URL_ESCAPE_SPACES_TOO:空格转义为%20URL_ESCAPE_UNSAFE:所有不安全字符统一转义
- 注意:该函数默认输出为RFC 3986格式编码,遍历输出字符串替换所有
%20子串为+,即可得到符合要求的form编码结果。
不建议手写百分号转义逻辑,系统原生API已经覆盖了所有保留字符、多字节编码的边界case,不会出现编码错误。
内容的提问来源于stack exchange,提问作者Club
相关产品推荐
相关产品推荐

