使用WinInet和WinHTTP调用服务器

时间:2010-03-12 11:58:28

标签: c++ wininet winhttp


当我使用WinInet API时,我的请求工作正常。我现在想用WinHTTP API发出请求,因为我已经在我的项目中使用它,因为它更好。我的请求用于调用JSON。我在调用之前已经过身份验证。在进行身份验证时,我会获得通过cookie发送的SessionID。
所以这是我工作的WinInet代码:

DWORD dwError;
HINTERNET hOpen = NULL, hReq = NULL;
hOpen = InternetOpen(_T(""), INTERNET_OPEN_TYPE_DIRECT, _T(""), _T(""), 0);
if(hOpen == NULL)
{
    dwError = GetLastError();
    return false;
}

CString cstrCookies = _T("Cookie: JSESSIONID=") + cstrSession;
CString cstr = _T("https://") + cstrServer + _T("/list/") + cstrFileOrFolder;
hReq = InternetOpenUrl(hOpen, cstr, cstrCookies, -1L,
    INTERNET_FLAG_SECURE | INTERNET_FLAG_NO_COOKIES, 0); // without NO_COOKIES I'll get a 401
if(hReq == NULL)
{
    dwError = GetLastError();
    InternetCloseHandle(hOpen);
    return false;
}

DWORD dwCode, dwCodeSize;
dwCodeSize = sizeof(DWORD);
if(!HttpQueryInfo(hReq, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &dwCode, &dwCodeSize, NULL))
{
    dwError = GetLastError();
    InternetCloseHandle(hReq);
    InternetCloseHandle(hOpen);
    return false;
}

InternetCloseHandle(hOpen);
InternetCloseHandle(hReq);
return dwCode == 200;

所以我现在想要使用WinHTTP API做同样的事情。这就是我现在所拥有的:

DWORD dwError = 0;
HINTERNET hConnect = NULL, hRequest = NULL;

hConnect = WinHttpConnect(m_hSession, cstrServer, INTERNET_DEFAULT_HTTPS_PORT, 0);
if (hConnect == NULL)
{
    return false;
}

hRequest = WinHttpOpenRequest(hConnect, NULL, cstrMethod + _T("/list/") + cstrFileOrFolder,
    NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE);
if (hRequest == NULL)
{
    WinHttpCloseHandle(hConnect);
    return false;
}

DWORD dwOptionValue = WINHTTP_DISABLE_COOKIES;
if (WinHttpSetOption(hRequest, WINHTTP_OPTION_DISABLE_FEATURE, &dwOptionValue,
    sizeof(dwOptionValue)) != TRUE)
{
    WinHttpCloseHandle(hConnect);
    WinHttpCloseHandle(hRequest);
    return false;
}

const CString cstrHeaders = _T("Cookie: JSESSIONID=") + cstrSession;
if (WinHttpAddRequestHeaders(hRequest, cstrHeaders, cstrHeaders.GetLength(),
    WINHTTP_ADDREQ_FLAG_ADD) != TRUE)
{
    WinHttpCloseHandle(hConnect);
    WinHttpCloseHandle(hRequest);
    return false;
}

if (WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, -1L, WINHTTP_NO_REQUEST_DATA, 0,
    0, 0) != TRUE)
{
    WinHttpCloseHandle(hConnect);
    WinHttpCloseHandle(hRequest);
    return false;
}

if (WinHttpReceiveResponse(hRequest, NULL) != TRUE)
{
    WinHttpCloseHandle(hConnect);
    WinHttpCloseHandle(hRequest);
    return false;
}

DWORD dwCode, dwCodeSize;
dwCodeSize = sizeof(DWORD);
if(!WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &dwCode, &dwCodeSize, NULL))
{
    WinHttpCloseHandle(hConnect);
    WinHttpCloseHandle(hRequest);
    return false;
}

WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hRequest);
return dwCode == 200;

通过后一次调用,我总是收到401,但是我应该像第一种方法那样获得200。我还发现当我没有指定INTERNET_FLAG_NO_COOKIES标志时,第一次调用我得到401。所以我怀疑cookie标题的内容是错误的。谁有人看到我做错了什么?或者两种方法有什么区别?
THX ...

3 个答案:

答案 0 :(得分:0)

看起来正确。 如果我是你,我会连接一个HTTP调试代理,如Fiddler,并检查和比较这两种方法的HTTP流量。这可能会指出你需要做什么。

答案 1 :(得分:0)

好的,我找到了。从我发布的代码中不明显......
字符串cstrMethod包含我之前从身份验证调用的响应头中提取的用户ID。然后,此id用于构造方法调用。现在的问题是用户ID来自响应头,所以它以\r\n结束。所以构造的方法调用也包含\r\n,因此用户ID错误我得到了401。
因此我必须先从标题中修剪用户id字符串,然后再将其用于进一步调用。 嗯,WinInet呼叫接受了\r\n,这有点奇怪。

答案 2 :(得分:0)

使用此链接(http://msdn.microsoft.com/en-us/library/windows/desktop/aa384068(v=vs.85).aspx)查找每种方法的等效项。