POST 请求使用 wstring 类型截断并使用字符串格式良好
Posted
技术标签:
【中文标题】POST 请求使用 wstring 类型截断并使用字符串格式良好【英文标题】:POST request trucated with wstring type and well formed using string 【发布时间】:2019-12-31 16:32:07 【问题描述】:我想使用带有 UTF-8 特殊字符(如 €
)的 Wininet 发出 POST 请求。
void sendArticle()
LPCWSTR browser = L"MyClientApp/1.0";
LPCWSTR domain = L"127.0.0.1";
LPCWSTR methode = L"POST";
LPCWSTR page = L"/shopping/article.php";
std::wstring strContentType = L"Content-Type: application/x-www-form-urlencoded; charset=utf-8";
LPCWSTR contentType = strContentType.c_str();
std::wstring dataStr = L"article=thecontent";
LPVOID data = (LPVOID)dataStr.c_str();
HINTERNET hInternet = InternetOpenW(browser, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
HINTERNET hConnection = InternetConnectW(hInternet, domain, 80, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 1);
HINTERNET hRequest = HttpOpenRequestW(hConnection, methode, page, NULL, NULL, NULL, 0, 1);
HttpSendRequestW(hRequest, contentType, strContentType.size(), data, dataStr.size());
如果我对变量dataStr
使用字符串类型,则内容发送正确。如果我对变量使用 wstring 类型(发送 UTF-8 内容),请求将被截断。
我可以使用 Wireshark 观察 TCP 数据包。
要恢复,这条线std::string dataStr = "article=thecontent";
有效,但这条线std::wstring dataStr = L"article=thecontent";
无效。
我检查了size()
方法返回的int,它是正确的。这是什么奇怪的现象,如何解决?
【问题讨论】:
根据文档here,HttpSendRequestW
的最后一个参数是字节的数量,而不是字符的数量。试试dataStr.size() * sizeof(WCHAR);
【参考方案1】:
HttpSendRequestW 采用 size in bytes 作为数据大小参数,但您使用的是宽字符串,所以您真的想要:
HttpSendRequestW(hRequest, contentType, strContentType.size(), data, sizeof(WCHAR)*dataStr.size());
但是,http 使用 utf8 确实可以正常工作,因此发送 utf16 有点奇怪(尽管您可以解释数据有效负载,但是您希望发送 utf16 是可以的)。
您真正想要做的只是发送 utf8 - 您可以使用窄字符串来做到这一点 - 只需将 dataStr 设为 std::string 并用 utf8 代码点填充它就可以了。
【讨论】:
感谢您的回答,确实我只想发送特殊字符,如€
或é
、à
...您能帮我获得正确的代码吗?
@ejeqaddoj-6455: std::string dataStr = u8"€";然后让其他一切保持不变。
嘿,我对你的回答很感兴趣,但问题是一样的。你能发布一个“交钥匙”解决方案吗?谢谢。【参考方案2】:
服务器需要 UTF8 数据 (dataStr
),因此必须将数据从 UTF16 转换为 UTF8。将其他所有内容保持为宽字符格式,因为这些函数由宽字符串 API 正确处理
//convert dataStr to UTF8
int sz = WideCharToMultiByte(CP_UTF8, 0, dataStr.c_str(), -1, 0, 0, 0, 0);
std::string utf8(sz, 0);
WideCharToMultiByte(CP_UTF8, 0, dataStr.c_str(), (int)dataStr.size(), &utf8[0], sz, 0, 0);
//send UTF8 data
HttpSendRequestW(hRequest, contentType, strContentType.size(), utf8.data(), utf8.size());
【讨论】:
感谢您的回答,代替使用 wstring 并将其转换为 UTF-8,使用 string 并将其作为 UTF-8 内容正常发送不是更合乎逻辑吗?你能帮我转换一下代码吗?谢谢。 使用u8"string"
嘿,我对你的回答很感兴趣,但问题是一样的。你能发布一个“交钥匙”解决方案吗?谢谢。【参考方案3】:
我遇到了同样的问题,这是我找到的解决方案,效果很好:
void sendHello()
LPCSTR header = "Content-Type: application/x-www-form-urlencoded; charset=utf-8";
std::string dataStr = u8"message=ééàà€€";
LPVOID myMessage = (LPVOID)dataStr.c_str();
HINTERNET hInternet = InternetOpenA("InetURL/1.0", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
HINTERNET hConnection = InternetConnectA(hInternet, "127.0.0.1", 80, " ", " ", INTERNET_SERVICE_HTTP, 0, 1);
HINTERNET hRequest = HttpOpenRequestA(hConnection, "POST", "/SendMessage.php", NULL, NULL, NULL, 0, 1);
HttpSendRequestA(hRequest, header, strlen(header), myMessage, dataStr.size());
【讨论】:
以上是关于POST 请求使用 wstring 类型截断并使用字符串格式良好的主要内容,如果未能解决你的问题,请参考以下文章
php ajax提交post请求出现数组被截断情况的解决方法
Asp.Net Post传的字符串太长,导致收到的时候被截断!
C++ 使用最少的代码将字符串转换为 wstring 并返回