首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >将WinHttp转换为WinInet API POST请求

将WinHttp转换为WinInet API POST请求
EN

Stack Overflow用户
提问于 2022-02-24 23:49:52
回答 1查看 226关注 0票数 0

我正在尝试将一些HTTP请求代码从使用WinHttp COM接口转换为使用来自<wininet.h>的低级WinInet调用。COM版本正在工作,但我很难将调用转换为WinInet API。

此代码工作正常,并获得对POST请求的正确错误响应(因为请求数据为空):

代码语言:javascript
运行
复制
#import <winhttpcom.dll>
#include <iostream>
#include <string>

int main()
{
    HRESULT hr = CoInitialize(NULL);

    using namespace WinHttp;
    IWinHttpRequestPtr pReq = NULL;

    hr = pReq.CreateInstance(__uuidof(WinHttpRequest));

    const char* pszReq = "";
    
    if (SUCCEEDED(hr))
    {
        _bstr_t bstrMethod("POST");
        _bstr_t bstrUrl("https://lite.realtime.nationalrail.co.uk/OpenLDBWS/ldb9.asmx");
        hr = pReq->Open(bstrMethod, bstrUrl);

        pReq->SetRequestHeader(_bstr_t("Content-Type"), _bstr_t("text/*"));

        _variant_t vReq(pszReq);
        hr = pReq->Send(vReq);
        if (SUCCEEDED(hr))
        {
            _bstr_t bstrResp;
            hr = pReq->get_ResponseText(&bstrResp.GetBSTR());
            if (SUCCEEDED(hr))
            {
                std::cout << std::string(bstrResp) << "\n";
            }
        }
    }
    CoUninitialize();
}

将输出保存为html,提供响应的呈现(这正是我所期望的,因为我没有提供任何请求数据,通常包括一个访问令牌)。

这是我用wininet.h和低级Win32调用(我意识到还没有关闭句柄)尝试复制这个结果的代码(在下面的注释之后进行修改,并且应该是可重复的)。

代码语言:javascript
运行
复制
#include <windows.h>
#include <WinInet.h>   
#include <iostream>
   
int main()
{
    const char* pszReq = "";
    const char* pszUrl = "https://lite.realtime.nationalrail.co.uk/OpenLDBWS/ldb9.asmx";

    char szHostName[256];
    char szPath[256];

    URL_COMPONENTSA comps = {};
    comps.dwStructSize = sizeof(comps);
    comps.lpszHostName = szHostName;
    comps.dwHostNameLength = sizeof(szHostName);
    comps.lpszUrlPath = szPath;
    comps.dwUrlPathLength = sizeof(szPath);

    if (!InternetCrackUrlA(pszUrl, strlen(pszUrl), 0, &comps)) return 1;

    HINTERNET hOpen = InternetOpenA("XYZ",INTERNET_OPEN_TYPE_DIRECT,NULL,NULL,0);
    if (!hOpen) return 1;

    HINTERNET hConnect = InternetConnectA(hOpen,szHostName,comps.nPort,
            NULL,NULL,INTERNET_SERVICE_HTTP,0,NULL);
    if (!hConnect) return 1;

    const char * rgpszAcceptTypes[] = { "text/*", NULL };    
    HINTERNET hOpenReq = HttpOpenRequestA(hConnect,"POST",szPath,NULL, NULL,
                rgpszAcceptTypes, 0,NULL);    
    
    if (!hOpenReq) return 1;

    const char* pszHeader = "Content-Type: text/xml;charset=UTF-8";

    //*** This line returns FALSE ***
    BOOL bRet = HttpSendRequestA(hOpenReq, pszHeader, strlen(pszHeader), (LPVOID)pszReq, strlen(pszReq));
    //*** LastError is ERROR_HTTP_INVALID_SERVER_RESPONSE
    DWORD dwErr = GetLastError();

    return 0;
}

所有的WinInet句柄都是非零的,这表明调用正常,但是最后一个HttpSendRequestA()立即返回FALSE,LastError设置为ERROR_HTTP_INVALID_SERVER_RESPONSE。

很明显,COM路由隐藏了许多中间工作,并且一些常量可能默认为特定值。我想,它还可能添加其他头信息。

也许有人能告诉我哪里出了问题?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-02-25 00:48:52

在WinInet代码中有一些错误:

  • pszServerName值需要仅仅是主机名,而不是完整的URL。如果您有一个URL作为输入,则可以使用InternetCrackUrlA()将其解析为其组成部分。
  • HttpOpenRequestA()的第三个参数是相对于pszServerName的请求资源。因此,在您的示例中,您需要使用"/"请求根资源。
  • HttpSendRequestA()的第一个参数需要是hOpenReq,而不是hOpen。此外,您不应该在缓冲区大小中包括空终止符。

如果您还没有这样做,您应该查看一下WinInet关于HTTP会话的文档。

说到这里,试试这个:

代码语言:javascript
运行
复制
#include <windows.h>
#include <WinInet.h>
#include <iostream>

const char * pszUrl = "https://someUrl";
const char * pszReq = "A string of request data";
const char* pszHeader = "Content-Type: text/xml;charset=UTF-8";

char szHostName[256];
char szPath[256];

URL_COMPONENTSA comps = {};
comps.dwStructSize = sizeof(comps);
comps.lpszHostName = szHostName;
comps.dwHostNameLength = sizeof(szHostName);
comps.lpszUrlPath = szPath;
comps.dwUrlPathLength = sizeof(szPath);

BOOL bRet = InternetCrackUrlA(pszUrl, strlen(pszUrl), 0, &comps);
if (!bRet) ...

HINTERNET hOpen = InternetOpenA("XYZ", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
if (!hOpen) ...

HINTERNET hConnect = InternetConnectA(hOpen, szHostName, comps.nPort, NULL, NULL, INTERNET_SERVICE_HTTP, 0, NULL);
if (!hConnect) ...

HINTERNET hOpenReq = HttpOpenRequestA(hConnect, "POST", szPath, NULL, NULL, NULL, comps.nScheme == INTERNET_SCHEME_HTTPS ? INTERNET_FLAG_SECURE : 0, NULL);
if (!hOpenReq) ...

bRet = HttpSendRequestA(hOpenReq, pszHeader, strlen(pszHeader), pszReq, strlen(pszReq));
if (!bRet) ...

...
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71259534

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档