1


当我使用 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标头有问题。有谁看到我做错了什么?或者这两种方法有什么区别?
谢谢...

4

2 回答 2

0

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

于 2010-03-12T12:07:43.290 回答
0

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

于 2010-03-15T13:54:02.363 回答