为什么在不同的连接(新的 InternetOpen 和新的 InternetConnect)上两次调用 HttpSendRequest 会带来不同的结果?

Why two calls to HttpSendRequest on different connections (new InternetOpen and new InternetConnect) bring different results?

我正在使用 wininet 连接到需要客户端证书的 url。为了测试我的 "automatic error correction",我在没有客户端证书的情况下进行此连接,行为是调用我的 SelectCertificate 函数。

我故意没有将所有参数传递给此函数,当然,这会引发异常并且我的请求被中止。有清理块来执行所有必要的清理 [InternetCloseHandle(HttpOpenRequestHandle)、InternetCloseHandle(InternetConnectHandle) 和 InternetCloseHandle(InternetOpenHandle)]。

第一个请求返回了正确的异常,这是由于缺少客户端证书引起的,但是第二个(新的?)请求引发了另一个异常"Secure Channel Support Error"(错误 12157)

为了澄清,请参阅以下流程:

第一个请求

1.0 InternetOpen(...)

2.0 InternetConnect(...)

3.0 HttpOpenRequest(...)

4.0 HttpSendRequest(..)

  4.1 Error (ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED)

  4.2 SelectCertificate

    4.2.1 Raise exception because I intentionally do not passed all parameters

5.0 InternetCloseHandle(HttpOpenRequestHandle)

6.0 InternetCloseHandle(InternetConnectHandle)

7.0 InternetCloseHandle(InternetOpenHandle);

第二个(新?)请求

1.0 InternetOpen(...)

2.0 InternetConnect(...)

3.0 HttpOpenRequest(...)

4.0 HttpSendRequest(..)

  4.1 Error (ERROR_INTERNET_SECURITY_CHANNEL_ERROR)

  4.2 I do not know how to handle this error, so...

  4.3 Raise the original exception "Secure Channel Support Error"

5.0 InternetCloseHandle(HttpOpenRequestHandle)

6.0 InternetCloseHandle(InternetConnectHandle)

7.0 InternetCloseHandle(InternetOpenHandle)

从现在开始的所有其他请求与第二个请求一样。

我的问题是:

因为我正在关闭所有句柄并执行 "totally new connection",调用之间的结果应该不一样?

如果不是,为什么?

有没有办法建立全新的连接?怎么样?

实际上,我只有关闭整个应用程序才能获得全新的连接 :( 并重新开始

问题是由某种 SSL 缓存引起的,可以通过在请求之前执行以下代码块来清除:

type
    TSslEmptyCache = function (pszTargetName: LPSTR; dwFlags: DWORD): BOOL; WINAPI;
    TIncrementUrlCacheHeaderData = function (nIdx: DWORD; lpdwData: LPDWORD): BOOL; WINAPI;

var
    SchannelDLLHandle, WinInetHandle: HMODULE;
    SslEmptyCache: TSslEmptyCache;
    IncrementUrlCacheHeaderData: TIncrementUrlCacheHeaderData;

SchannelDLLHandle := LoadLibrary('schannel.dll');
WinInetHandle := LoadLibrary('wininet.dll');

if (SchannelDLLHandle > 0) and (WinInetHandle > 0) then
    try
    SslEmptyCache := GetProcAddress(SchannelDLLHandle,'SslEmptyCacheW');
    IncrementUrlCacheHeaderData := GetProcAddress(WinInetHandle,'IncrementUrlCacheHeaderData');
    if Assigned(SslEmptyCache) and Assigned(IncrementUrlCacheHeaderData) then
    begin
      SslEmptyCache(nil,0);
      IncrementUrlCacheHeaderData(14,@buffer);
    end;
    finally
        FreeLibrary(SchannelDLLHandle);
    FreeLibrary(WinInetHandle);
    end;

有关详细信息,请阅读 this article