C++ C++;WinHttp获取响应头和响应体

C++ C++;WinHttp获取响应头和响应体,c++,winapi,httprequest,httpresponse,winhttp,C++,Winapi,Httprequest,Httpresponse,Winhttp,我目前正在尝试编写一个类,使发送简单请求变得更容易。 最后,我希望它可以像这样使用: int _tmain(int argc, _TCHAR* argv[]) { HttpRequest Request(L"Example UserAgent/1.0",L"",L""); Request.SendRequest(L"google.com",L"GET",NULL); if (Request.responseHeader) printf("%s",Reque

我目前正在尝试编写一个类,使发送简单请求变得更容易。
最后,我希望它可以像这样使用:

int _tmain(int argc, _TCHAR* argv[])
{
    HttpRequest Request(L"Example UserAgent/1.0",L"",L"");
    Request.SendRequest(L"google.com",L"GET",NULL);
    if (Request.responseHeader)
        printf("%s",Request.responseHeader);
    if (Request.responseBody)
        printf("%s",Request.responseBody);
    getchar();
    return 0;
}
但现在它根本不起作用。我不知道如何获取响应头,我无法将响应头写入我的类的公共成员。
是的,我对C++非常的不好,尤其是关于WiAPI的。 我希望你能帮助我。
以下是我目前的代码:

#include "stdafx.h"
#include <windows.h>
#include <winhttp.h>
#pragma comment(lib, "winhttp.lib")

class HttpRequest {
  private:
    DWORD dwSize;
    DWORD dwDownloaded;
    LPSTR pszOutBuffer;
    BOOL  bResults;
    HINTERNET hSession;
    HINTERNET hConnect;
    HINTERNET hRequest;
    LPCWSTR _userAgent;
    //LPCWSTR _proxyIp;
    //LPCWSTR _proxyPort;
    size_t bodySize;
  public:
    HttpRequest(LPCWSTR, LPCWSTR, LPCWSTR);
    void SendRequest(LPCWSTR, LPCWSTR, LPVOID);
    LPSTR responseHeader[1000000];
    LPSTR responseBody[1000000];
};

HttpRequest::HttpRequest(LPCWSTR userAgent, LPCWSTR proxyIp, LPCWSTR proxyPort) {
    _userAgent = userAgent;
    //_proxyIp = proxyIp;
    //_proxyPort = proxyPort;
    hSession = WinHttpOpen( userAgent, WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0 );
}

void HttpRequest::SendRequest(LPCWSTR url, LPCWSTR method, LPVOID body) {
    bodySize = 0;
    if (hSession)
        hConnect = WinHttpConnect( hSession, url, INTERNET_DEFAULT_HTTPS_PORT, 0 );
    else
        printf("session handle failed\n");
    if (hConnect)
        hRequest = WinHttpOpenRequest( hConnect, method, NULL, NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE );
    else
        printf("connect handle failed\n");
    if (hRequest)
        bResults = WinHttpSendRequest( hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, body, 0, 0, 0 );
    else
        printf("request handle failed\n");

    if( bResults )
        bResults = WinHttpReceiveResponse( hRequest, NULL );
    if( bResults )
    {
        do 
        {
            // Check for available data.
            dwSize = 0;
            if( !WinHttpQueryDataAvailable( hRequest, &dwSize ) )
                printf( "Error %u in WinHttpQueryDataAvailable.\n", GetLastError( ) );

            // Allocate space for the buffer.
            pszOutBuffer = new char[dwSize+1];
            if( !pszOutBuffer )
            {
                printf( "Out of memory\n" );
                dwSize=0;
            }
            else
            {
                // Read the data.
                ZeroMemory( pszOutBuffer, dwSize+1 );

                if( !WinHttpReadData( hRequest, (LPVOID)pszOutBuffer, dwSize, &dwDownloaded ) )
                    printf( "Error %u in WinHttpReadData.\n", GetLastError( ) );
                else { 
                    //printf( "%s", pszOutBuffer );
                    responseBody[bodySize++] = pszOutBuffer; 
                }
                // Free the memory allocated to the buffer.
                delete [] pszOutBuffer;
            }
        } while( dwSize > 0 );
    }

    // Report any errors.
    if( !bResults )
        printf( "Error %d has occurred.\n", GetLastError( ) );

    // Close any open handles.
    if( hRequest ) WinHttpCloseHandle( hRequest );
    if( hConnect ) WinHttpCloseHandle( hConnect );
    if( hSession ) WinHttpCloseHandle( hSession );
}
#包括“stdafx.h”
#包括
#包括
#pragma注释(lib,“winhttp.lib”)
类HttpRequest{
私人:
DWORD dwSize;
德沃德·德沃德;
LPSTR-pszOutBuffer;
布尔结果;
腹地会话;
腹地连接;
腹地探索;
LPCWSTR_用户代理;
//LPCWSTR_proxyIp;
//LPCWSTR\u代理端口;
大小与体型;
公众:
HttpRequest(LPCWSTR,LPCWSTR,LPCWSTR);
无效发送请求(LPCWSTR、LPCWSTR、LPVOID);
LPSTR负责人[1000000];
LPSTR响应库[1000000];
};
HttpRequest::HttpRequest(LPCWSTR用户代理、LPCWSTR代理、LPCWSTR代理){
_userAgent=userAgent;
//_proxyIp=proxyIp;
//_proxyPort=proxyPort;
hsSession=WinHttpOpen(用户代理、WINHTTP\u访问类型、默认代理、WINHTTP\u无代理、WINHTTP\u无代理、0);
}
void HttpRequest::SendRequest(LPCWSTR url、LPCWSTR方法、LPVOID正文){
体型=0;
如果(hsSession)
hConnect=WinHttpConnect(会话、url、INTERNET\u默认\u HTTPS\u端口,0);
其他的
printf(“会话句柄失败\n”);
如果(hConnect)
hRequest=WinHttpOpenRequest(hConnect,method,NULL,NULL,WINHTTP\u NO\u REFERER,WINHTTP\u DEFAULT\u ACCEPT\u type,WINHTTP\u FLAG\u SECURE);
其他的
printf(“连接句柄失败\n”);
如果(hRequest)
bResults=WinHttpSendRequest(hRequest,WINHTTP_无附加_头,0,正文,0,0);
其他的
printf(“请求句柄失败\n”);
如果(b结果)
bResults=WinHttpReceiveResponse(hRequest,NULL);
如果(b结果)
{
做
{
//检查可用数据。
dwSize=0;
如果(!WinHttpQueryDataAvailable(hRequest和dwSize))
printf(“WinHttpQueryDataAvailable中的错误%u。\n”,GetLastError());
//为缓冲区分配空间。
pszOutBuffer=新字符[dwSize+1];
如果(!pszOutBuffer)
{
printf(“内存不足\n”);
dwSize=0;
}
其他的
{
//读取数据。
零内存(pszOutBuffer,dwSize+1);
if(!WinHttpReadData(hRequest,(LPVOID)pszOutBuffer、dwSize和dwDownloaded))
printf(“WinHttpReadData中的错误%u。\n”,GetLastError());
否则{
//printf(“%s”,pszOutBuffer);
responseBody[bodySize++]=pszOutBuffer;
}
//释放分配给缓冲区的内存。
删除[]pszOutBuffer;
}
}而(dwSize>0);
}
//报告任何错误。
如果(!bResults)
printf(“发生了错误%d。\n”,GetLastError());
//关闭所有打开的手柄。
if(hRequest)WinHttpCloseHandle(hRequest);
if(hConnect)WinHttpCloseHandle(hConnect);
if(hSession)WinHttpCloseHandle(hSession);
}
用于访问响应标题。使用
WINHTTP\u QUERY\u RAW\u头(\u CRLF)
标志指定要检索所有可用头

您还需要更改类以动态分配其
responseHeader
responseBody
成员。使用静态数组不仅浪费了大量内存,而且限制了可以处理的响应大小

试试这个:

#include "stdafx.h"
#include <windows.h>
#include <winhttp.h>
#include <string>
#include <vector>

#pragma comment(lib, "winhttp.lib")

class HttpRequest
{
private:
    std::wstring _userAgent;
    //std::wstring _proxyIp;
    //std::wstring _proxyPort;
public:
    HttpRequest(const std::wstring&, const std::wstring&, const std::wstring&);
    bool SendRequest(const std::wstring&, const std::wstring&, void*, DWORD);
    std::wstring responseHeader;
    std::vector<BYTE> responseBody;
};

HttpRequest::HttpRequest(const std::wstring &userAgent, const std::wstring &proxyIp, const std::wstring &proxyPort) :
    _userAgent(userAgent)
    //,_proxyIp(proxyIp)
    //,_proxyPort(proxyPort)
{
}

bool HttpRequest::SendRequest(const std::wstring &url, const std::wstring &method, void *body, DWORD bodySize)
{
    DWORD dwSize;
    DWORD dwDownloaded;
    DWORD headerSize = 0;
    BOOL  bResults = FALSE;
    HINTERNET hSession;
    HINTERNET hConnect;
    HINTERNET hRequest;

    responseHeader.resize(0);
    responseBody.resize(0);

    hSession = WinHttpOpen( _userAgent.c_str(), WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0 );
    if (hSession)
        hConnect = WinHttpConnect( hSession, url.c_str(), INTERNET_DEFAULT_HTTPS_PORT, 0 );
    else
        printf("session handle failed\n");

    if (hConnect)
        hRequest = WinHttpOpenRequest( hConnect, method.c_str(), NULL, NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE );
    else
        printf("connect handle failed\n");

    if (hRequest)
        bResults = WinHttpSendRequest( hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, body, bodySize, 0, 0 );
    else
        printf("request handle failed\n");

    if (bResults)
        bResults = WinHttpReceiveResponse( hRequest, NULL );
    if (bResults)
    {
        bResults = WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_RAW_HEADERS_CRLF, NULL, WINHTTP_NO_OUTPUT_BUFFER, &headerSize, WINHTTP_NO_HEADER_INDEX);
        if ((!bResults) && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
        {
            responseHeader.resize(headerSize / sizeof(wchar_t));
            if (responseHeader.empty())
            {
                bResults = TRUE;
            }
            else
            {
                bResults = WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_RAW_HEADERS_CRLF, NULL, &responseHeader[0], &headerSize, WINHTTP_NO_HEADER_INDEX);
                if( !bResults ) headerSize = 0;
                responseHeader.resize(headerSize / sizeof(wchar_t));
            }
        }
    }
    if (bResults)
    {
        do
        {
            // Check for available data.
            dwSize = 0;
            bResults = WinHttpQueryDataAvailable( hRequest, &dwSize );
            if (!bResults)
            {
                printf( "Error %u in WinHttpQueryDataAvailable.\n", GetLastError( ) );
                break;
            }

            if (dwSize == 0)
                break;

            do
            {
                // Allocate space for the buffer.
                DWORD dwOffset = responseBody.size();
                responseBody.resize(dwOffset+dwSize);

                // Read the data.
                bResults = WinHttpReadData( hRequest, &responseBody[dwOffset], dwSize, &dwDownloaded );
                if (!bResults)
                {
                    printf( "Error %u in WinHttpReadData.\n", GetLastError( ) );
                    dwDownloaded = 0;
                }

                responseBody.resize(dwOffset+dwDownloaded);

                if (dwDownloaded == 0)
                    break;

                dwSize -= dwDownloaded;
            }
            while (dwSize > 0);
        }
        while (true);
    }

    // Report any errors.
    if (!bResults)
        printf( "Error %d has occurred.\n", GetLastError( ) );

    // Close any open handles.
    if( hRequest ) WinHttpCloseHandle( hRequest );
    if( hConnect ) WinHttpCloseHandle( hConnect );
    if( hSession ) WinHttpCloseHandle( hSession );

    return bResults;
}
用于访问响应标题。使用
WINHTTP\u QUERY\u RAW\u头(\u CRLF)
标志指定要检索所有可用头

您还需要更改类以动态分配其
responseHeader
responseBody
成员。使用静态数组不仅浪费了大量内存,而且限制了可以处理的响应大小

试试这个:

#include "stdafx.h"
#include <windows.h>
#include <winhttp.h>
#include <string>
#include <vector>

#pragma comment(lib, "winhttp.lib")

class HttpRequest
{
private:
    std::wstring _userAgent;
    //std::wstring _proxyIp;
    //std::wstring _proxyPort;
public:
    HttpRequest(const std::wstring&, const std::wstring&, const std::wstring&);
    bool SendRequest(const std::wstring&, const std::wstring&, void*, DWORD);
    std::wstring responseHeader;
    std::vector<BYTE> responseBody;
};

HttpRequest::HttpRequest(const std::wstring &userAgent, const std::wstring &proxyIp, const std::wstring &proxyPort) :
    _userAgent(userAgent)
    //,_proxyIp(proxyIp)
    //,_proxyPort(proxyPort)
{
}

bool HttpRequest::SendRequest(const std::wstring &url, const std::wstring &method, void *body, DWORD bodySize)
{
    DWORD dwSize;
    DWORD dwDownloaded;
    DWORD headerSize = 0;
    BOOL  bResults = FALSE;
    HINTERNET hSession;
    HINTERNET hConnect;
    HINTERNET hRequest;

    responseHeader.resize(0);
    responseBody.resize(0);

    hSession = WinHttpOpen( _userAgent.c_str(), WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0 );
    if (hSession)
        hConnect = WinHttpConnect( hSession, url.c_str(), INTERNET_DEFAULT_HTTPS_PORT, 0 );
    else
        printf("session handle failed\n");

    if (hConnect)
        hRequest = WinHttpOpenRequest( hConnect, method.c_str(), NULL, NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE );
    else
        printf("connect handle failed\n");

    if (hRequest)
        bResults = WinHttpSendRequest( hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, body, bodySize, 0, 0 );
    else
        printf("request handle failed\n");

    if (bResults)
        bResults = WinHttpReceiveResponse( hRequest, NULL );
    if (bResults)
    {
        bResults = WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_RAW_HEADERS_CRLF, NULL, WINHTTP_NO_OUTPUT_BUFFER, &headerSize, WINHTTP_NO_HEADER_INDEX);
        if ((!bResults) && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
        {
            responseHeader.resize(headerSize / sizeof(wchar_t));
            if (responseHeader.empty())
            {
                bResults = TRUE;
            }
            else
            {
                bResults = WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_RAW_HEADERS_CRLF, NULL, &responseHeader[0], &headerSize, WINHTTP_NO_HEADER_INDEX);
                if( !bResults ) headerSize = 0;
                responseHeader.resize(headerSize / sizeof(wchar_t));
            }
        }
    }
    if (bResults)
    {
        do
        {
            // Check for available data.
            dwSize = 0;
            bResults = WinHttpQueryDataAvailable( hRequest, &dwSize );
            if (!bResults)
            {
                printf( "Error %u in WinHttpQueryDataAvailable.\n", GetLastError( ) );
                break;
            }

            if (dwSize == 0)
                break;

            do
            {
                // Allocate space for the buffer.
                DWORD dwOffset = responseBody.size();
                responseBody.resize(dwOffset+dwSize);

                // Read the data.
                bResults = WinHttpReadData( hRequest, &responseBody[dwOffset], dwSize, &dwDownloaded );
                if (!bResults)
                {
                    printf( "Error %u in WinHttpReadData.\n", GetLastError( ) );
                    dwDownloaded = 0;
                }

                responseBody.resize(dwOffset+dwDownloaded);

                if (dwDownloaded == 0)
                    break;

                dwSize -= dwDownloaded;
            }
            while (dwSize > 0);
        }
        while (true);
    }

    // Report any errors.
    if (!bResults)
        printf( "Error %d has occurred.\n", GetLastError( ) );

    // Close any open handles.
    if( hRequest ) WinHttpCloseHandle( hRequest );
    if( hConnect ) WinHttpCloseHandle( hConnect );
    if( hSession ) WinHttpCloseHandle( hSession );

    return bResults;
}

非常感谢。不过向量似乎有问题。我从未使用过向量,我不确定我是否理解它们。我得到以下错误:调试断言失败文件:c:\program files(x86)\microsoft visual studio 10.0\vc\include\vector |行:932 |表达式:矢量下标超出范围。。。我还想知道如何获得请求正文的字节大小,以及是否可以在函数中计算它。这是修改后的版本:请求和响应被正确发送,应用程序只是因为向量而失败…当我尝试它时,工作正常,没有超出范围的错误。不过,我已经为您调整了代码,以防万一。当
SendRequest()
返回true时,您可以通过
responseBody.size()
检索正文大小。并非总是能够提前获得正文大小,例如,当使用HTTP的
传输编码:chunked
头时。所以你只要一直读到回应的结尾,我不明白,为什么只有我会得到这个错误。这怎么可能?我会做错什么?这就是调试器的作用。我以前从未使用过向量。我完全不知道它们是如何工作的。[…]如果(size(),谢谢。但向量似乎有问题。我从未使用过向量,也不确定是否理解它们。我收到以下错误:调试断言失败!|文件:c:\program files(x86)\microsoft visual studio 10.0\vc\include\vector | Line:932 |表达式:向量下标超出范围…我还想知道如何获得请求正文的字节大小,以及是否可以在函数中计算它。H