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请求出现数组被截断情况的解决方法

springboot post请求参数中有&还是被截断

Asp.Net Post传的字符串太长,导致收到的时候被截断!

C++ 使用最少的代码将字符串转换为 wstring 并返回

IT兄弟连 JavaWeb教程 使用AJAX发送POST请求并获取响应

非post请求时整个url作为参数传递出现bug