转 C++编程笔记:使用WinHTTP实现HTTP访问(解决接收UTF8数据乱码问题)

实现HTTP访问的流程包括以下几步:
1, 首先我们打开一个Session获得一个HINTERNET session句柄;
2, 然后我们使用这个session句柄与服务器连接得到一个HINTERNET connect句柄;
3, 然后我们使用这个connect句柄来打开Http请求得到一个HINTERNET request句柄;
4, 这时我们就可以使用这个request句柄来发送数据与读取从服务器返回的数据;
5, 最后依次关闭request,connect,session句柄。

微软提供了两套http访问的接口:WinHTTP和WinINet。WinHTTP比WinINet更加安全和健壮,可以认为WinHTTP是WinINet的升级版本。这两套API包含了很多相似的函数与宏定义,访问的流程也是完全类似的(上述5步)。本文主要通过WinHTTP实现post请求方法,严格按照上述5个步骤给大家进行讲解。
又由于我所接收到的数据是UTF8而不是ASCII码,因此一开始接收到的数据存在乱码。在下述代码中我会详细解释出现乱码的原因以及如何解决。
好,小二,上代码!

#include “stdafx.h”
#include “jsonparser.h”

#include
#include
#include
#pragma comment(lib, “winhttp.lib”)

int _tmain(int argc, _TCHAR* argv[])
{
HINTERNET hSession = NULL;
HINTERNET hConnect = NULL;
HINTERNET hRequest = NULL;

//1. 初始化一个WinHTTP-session句柄,参数1为此句柄的名称
hSession = WinHttpOpen(L"csdn@elaine_bao", NULL, NULL, NULL, NULL);
if (hSession == NULL) {
    cout<<"Error:Open session failed: "<(ss), data.length(), data.length(), 0);
if (!bResults){
    cout << "Error:SendRequest failed: " << GetLastError() << endl;
    return -1;
}
else{
    //(3) 发送请求成功则准备接受服务器的response。注意:在使用 WinHttpQueryDataAvailable和WinHttpReadData前必须使用WinHttpReceiveResponse才能access服务器返回的数据
    bResults = WinHttpReceiveResponse(hRequest, NULL);
}

//4-2. 获取服务器返回数据的header信息。这一步我用来获取返回数据的数据类型。
LPVOID lpHeaderBuffer = NULL;
DWORD dwSize = 0;   
if (bResults)
{
    //(1) 获取header的长度
    WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_RAW_HEADERS_CRLF,
        WINHTTP_HEADER_NAME_BY_INDEX, NULL,
        &dwSize, WINHTTP_NO_HEADER_INDEX);

    //(2) 根据header的长度为buffer申请内存空间
    if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
    {
        lpHeaderBuffer = new WCHAR[dwSize / sizeof(WCHAR)];

        //(3) 使用WinHttpQueryHeaders获取header信息
        bResults = WinHttpQueryHeaders(hRequest,
            WINHTTP_QUERY_RAW_HEADERS_CRLF,
            WINHTTP_HEADER_NAME_BY_INDEX,
            lpHeaderBuffer, &dwSize,
            WINHTTP_NO_HEADER_INDEX);
    }
}
printf("Header contents: \n%S", lpHeaderBuffer);

//解析上述header信息会发现服务器返回数据的charset为uft-8。这意味着后面需要对获取到的raw data进行宽字符转换。一开始由于没有意识到需要进行转换所以得到的数据都是乱码。
//出现乱码的原因是:HTTP在传输过程中是二值的,它并没有text或者是unicode的概念。HTTP使用7bit的ASCII码作为HTTP headers,但是内容是任意的二值数据,需要根据header中指定的编码方式来描述它(通常是Content-Type header).
//因此当你接收到原始的HTTP数据时,先将其保存到char[] buffer中,然后利用WinHttpQueryHearders()获取HTTP头,得到内容的Content-Type,这样你就知道数据到底是啥类型的了,是ASCII还是Unicode或者其他。
//一旦你知道了具体的编码方式,你就可以通过MultiByteToWideChar()将其转换成合适编码的字符,存入wchar_t[]中。
//关于乱码的解决方案请看4-4

//4-3. 获取服务器返回数据
LPSTR pszOutBuffer = NULL;
DWORD dwDownloaded = 0;         //实际收取的字符数
wchar_t *pwText = NULL;
if (bResults)
{
    do
    {
        //(1) 获取返回数据的大小(以字节为单位)
        dwSize = 0;
        if (!WinHttpQueryDataAvailable(hRequest, &dwSize)){
            cout << "Error:WinHttpQueryDataAvailable failed:" << GetLastError() << endl;
            break;
        }           
        if (!dwSize)    break;  //数据大小为0                

        //(2) 根据返回数据的长度为buffer申请内存空间
        pszOutBuffer = new char[dwSize + 1];
        if (!pszOutBuffer){
            cout<<"Out of memory."< 0);

    //4-4. 将返回数据转换成UTF8
    DWORD dwNum = MultiByteToWideChar(CP_ACP, 0, pszOutBuffer, -1, NULL, 0);    //返回原始ASCII码的字符数目       
    pwText = new wchar_t[dwNum];                                                //根据ASCII码的字符数分配UTF8的空间
    MultiByteToWideChar(CP_UTF8, 0, pszOutBuffer, -1, pwText, dwNum);           //将ASCII码转换成UTF8
    printf("Received contents: \n%S", pwText);
}


//5. 依次关闭request,connect,session句柄
if (hRequest) WinHttpCloseHandle(hRequest);
if (hConnect) WinHttpCloseHandle(hConnect);
if (hSession) WinHttpCloseHandle(hSession);


return 0;

}

作者:Elaine_Bao
来源:CSDN
原文:https://blog.csdn.net/elaine_bao/article/details/51754882
版权声明:本文为博主原创文章,转载请附上博文链接!

你可能感兴趣的:(转 C++编程笔记:使用WinHTTP实现HTTP访问(解决接收UTF8数据乱码问题))