HttpSendRequestA 为假且 return 0

HttpSendRequestA is false and return 0

你好,我正在尝试使用 WinInet 和 costum 用户代理下载一些东西,问题是我在 HttpSendRequestA 失败,错误 return 是 0 我不知道这个错误是什么意思我已经尝试查找它但没有出现 我使用 std::to_string(GetLastError()); 得到错误 下面是代码

std::string GetUrlData(const std::string& resource, const std::string& host)
{
    std::string output = "";
    output.clear();

    HINTERNET hIntSession = InternetOpenA("token", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
    if (!hIntSession) {
        return "ERROR: Session Cannot Start";
    }

    HINTERNET hHttpSession = InternetConnectA(hIntSession, host.c_str(), 80, 0, 0, INTERNET_SERVICE_HTTP, 0, NULL);
    if (!hHttpSession) {
        InternetCloseHandle(hIntSession);
        return "ERROR: Cannot Connect To Internet";
    }

    HINTERNET hHttpRequest = HttpOpenRequestA(hHttpSession, "GET", resource.c_str(), 0, 0, 0, INTERNET_FLAG_RELOAD, 0);
    if (!hHttpRequest) {
        InternetCloseHandle(hHttpSession);
        InternetCloseHandle(hIntSession);
        return "ERROR: Http Request Failed";
    }

   // const char* szHeaders = "User-Agent: Mozzila\r\n";
    if (!HttpSendRequestA(hHttpRequest, NULL, 0, NULL, 0)) {
        InternetCloseHandle(hHttpRequest);
        InternetCloseHandle(hHttpSession);
        InternetCloseHandle(hIntSession);
        return "ERROR: Http Request Failed 2";

    }

    char szBuffer[1024];
    DWORD dwRead = 0;

    do {
        if (!InternetReadFile(hHttpRequest, szBuffer, sizeof(szBuffer), &dwRead)) {
            InternetCloseHandle(hHttpRequest);
            InternetCloseHandle(hHttpSession);
            InternetCloseHandle(hIntSession);
            return "ERROR: Cannot Download";
        }

        if (dwRead == 0)
            break;

        output.append(szBuffer, dwRead);
    }
    while (true);
    return output;
}

我这样称呼这个函数std::string data = GetUrlData("http://example.com/", "http://example.com/");

问题是你的 host 参数应该只是主机名,而不是完整的 URL 并且资源应该只是主机上的资源部分。

像这样:

std::string data = GetUrlData("/", "example.com");

旁注:您获得了最多三个需要手动释放的资源,并尝试确保使用 InternetCloseHandle() 释放它们,但它很快就会变得冗长,您最终可能会忘记一个。碰巧的是,如果您的 GetUrlData() 调用成功,您不会释放 任何 资源。

考虑将每个资源包装在 std::unique_ptr 中以使其自动释放。它不仅使它更安全,还使代码更易于阅读和维护。

示例:

#include <Windows.h>
#include <wininet.h>

#include <iostream>
#include <memory>
#include <stdexcept>
#include <string>
#include <type_traits>
// custom deleter for the resource
struct internet_deleter {
    void operator()(HINTERNET hi) { InternetCloseHandle(hi); }
};

// the resource's wrapper type
using ihandle = std::unique_ptr<std::remove_pointer_t<HINTERNET>, internet_deleter>;

// functions for acquiring resources
auto RAII_InternetOpen() {
    ihandle rv(InternetOpenA("token", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0));

    if (rv) return rv;

    throw std::runtime_error("InternetOpenA: " + std::to_string(GetLastError()));
}

auto RAII_InternetConnect(const ihandle& hIntSession, const std::string& host) {
    ihandle rv(
        InternetConnectA(hIntSession.get(), host.c_str(), 80, 0, 0,
                         INTERNET_SERVICE_HTTP, 0, NULL));
    if (rv) return rv;

    throw std::runtime_error("InternetConnectA: " + std::to_string(GetLastError()));
}

auto RAII_HttpOpenRequest(const ihandle& hHttpSession, const std::string& resource) {
    ihandle rv(
        HttpOpenRequestA(hHttpSession.get(), "GET", resource.c_str(), 0, 0, 0,
                         INTERNET_FLAG_RELOAD, 0));
    if (rv) return rv;

    throw std::runtime_error("HttpOpenRequestA: " + std::to_string(GetLastError()));
}

加上以上三个函数,GetUrlData()函数变得更简单,不会泄露资源:

std::string GetUrlData(const std::string& resource, const std::string& host)
{
    std::string output;

    auto hIntSession = RAII_InternetOpen();
    auto hHttpSession = RAII_InternetConnect(hIntSession, host);
    auto hHttpRequest = RAII_HttpOpenRequest(hHttpSession, resource);

    if (!HttpSendRequestA(hHttpRequest.get(), NULL, 0, NULL, 0))
        throw std::runtime_error("HttpSendRequestA: " + 
                                 std::to_string(GetLastError()));

    char szBuffer[1024];
    DWORD dwRead = 0;

    do {
        if (!InternetReadFile(hHttpRequest.get(), szBuffer, sizeof(szBuffer), &dwRead))
            throw std::runtime_error("InternetReadFile: " +
                                     std::to_string(GetLastError()));

        if (dwRead == 0)
            break;

        output.append(szBuffer, dwRead);
    } while (true);

    return output;
}

int main() {
    try {
        std::cout << GetUrlData("/", "www.google.com");
    }
    catch (const std::exception& ex) {
        std::cerr << "Exception: " << ex.what() << '\n';
    }
}