zoukankan      html  css  js  c++  java
  • 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 <string>
    #include <windows.h>
    #include <winhttp.h>
    #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: "<<GetLastError()<<endl;
            return -1;
        }
     
        //2. 通过上述句柄连接到服务器,需要指定服务器IP和端口号。若连接成功,返回的hConnect句柄不为NULL
        hConnect = WinHttpConnect(hSession, L"192.168.50.112", (INTERNET_PORT)8080, 0);
        if (hConnect == NULL) {
            cout << "Error:Connect failed: " << GetLastError()<<endl;
            return -1;
        }
     
        //3. 通过hConnect句柄创建一个hRequest句柄,用于发送数据与读取从服务器返回的数据。
        hRequest = WinHttpOpenRequest(hConnect, L"Post", L"getServiceInfo", NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, 0);
        //其中参数2表示请求方式,此处为Post;参数3:给定Post的具体地址,如这里的具体地址为http://192.168.50.112/getServiceInfo
        if (hRequest == NULL) {
            cout << "Error:OpenRequest failed: " << GetLastError() << endl;
            return -1;
        }
     
        //4-1. 向服务器发送post数据
        //(1) 指定发送的数据内容
        string data = "This is my data to be sent"; 
        const void *ss = (const char *)data.c_str();
     
        //(2) 发送请求
        BOOL bResults;
        bResults = WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, const_cast<void*>(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: 
    %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."<<endl;
                    break;
                }
                ZeroMemory(pszOutBuffer, dwSize + 1);       //将buffer置0
     
                //(3) 通过WinHttpReadData读取服务器的返回数据
                if (!WinHttpReadData(hRequest,pszOutBuffer, dwSize, &dwDownloaded)){
                    cout << "Error:WinHttpQueryDataAvailable failed:" << GetLastError() << endl;
                }
                if (!dwDownloaded)
                    break;
     
            } while (dwSize > 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: 
    %S", pwText);
        }
     
     
        //5. 依次关闭request,connect,session句柄
        if (hRequest) WinHttpCloseHandle(hRequest);
        if (hConnect) WinHttpCloseHandle(hConnect);
        if (hSession) WinHttpCloseHandle(hSession);
     
     
        return 0;
    }
  • 相关阅读:
    几维安全SDK应用加固,全线5折为APP保驾护航
    物联网渗透测试威胁建模,捕捉应用相关安全风险
    【几维安全】Android代码混淆,代码混淆工具,Android版使用详细说明
    畅想物联网安全未来,几维安全让万物互联更安全
    域起网络携手几维安全,护航互联网游戏业务安全
    Android 加密, Android 常用加密, Android So 库高强度加密
    车联网安全威胁分析及防护思路,几维安全为智能汽车保驾护航
    C#实现基于ffmpeg加虹软的人脸识别
    OSX 下搭建Asp.Net vNext的开发环境
    验证码识别记录
  • 原文地址:https://www.cnblogs.com/ruingking/p/13185481.html
Copyright © 2011-2022 走看看