我有一个爬虫,用于HTTP切换到Wininet。
这通常效果很好,但对于网站我会收到错误 ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED
示例代码:
vErrorNone := HttpSendRequest(HttpOpen_Request, nil, 0, nil, 0);
if vErrorNone = False then
begin
vErrorID := GetLastError;
if (vErrorID = ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED) then
begin
// this error
end
;
end
;
然后我尝试了一个实验:
TmpFakePointer := nil;
vErrorNone :=
InternetErrorDlg(
GetDesktopWindow()
,
HttpOpen_Request
,
ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED
,
0
or FLAGS_ERROR_UI_FILTER_FOR_ERRORS
or FLAGS_ERROR_UI_FLAGS_GENERATE_DATA
or FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS
,
TmpFakePointer
)
= ERROR_SUCCESS
;
if vErrorNone then
begin
vErrorNone := HttpSendRequest(HttpOpen_Request, nil, 0, nil, 0);
end
;
然而,这里有两件事情很奇怪:
它发现上面的组合很奇怪而且与文档相反。由于用户没有选择任何证书,为什么这样做?如果Wininet在无法显示对话框时回退到匿名客户端身份验证证书(我假设我已经给它显示对话框的错误句柄了?虽然如果我明确地给它一个错误的句柄它会出错)是否有任何方法可以直接选择没有调用InternetErrorDlg?
答案 0 :(得分:2)
好
您可以做两件事:
1:向用户显示证书错误,让他决定是否继续。
2:忽略您获得的任何证书错误。
我将告诉你如何做第二个选择:
当您收到ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED
或任何其他证书错误时,您需要致电InternetSetOptions
告诉wininet它应该忽略该错误并继续。之后,您必须重新发送请求。
function SetToIgnoreCerticateErrors(var aErrorMsg: string): Boolean;
var
vDWFlags: DWord;
vDWFlagsLen: DWord;
begin
Result := False;
try
vDWFlagsLen := SizeOf(vDWFlags);
if not InternetQueryOptionA(oRequestHandle, INTERNET_OPTION_SECURITY_FLAGS, @vDWFlags, vDWFlagsLen) then begin
aErrorMsg := 'Internal error in SetToIgnoreCerticateErrors when trying to get wininet flags.' + GetWininetError;
Exit;
end;
vDWFlags := vDWFlags or SECURITY_FLAG_IGNORE_UNKNOWN_CA or SECURITY_FLAG_IGNORE_CERT_DATE_INVALID or SECURITY_FLAG_IGNORE_CERT_CN_INVALID or SECURITY_FLAG_IGNORE_REVOCATION;
if not InternetSetOptionA(oRequestHandle, INTERNET_OPTION_SECURITY_FLAGS, @vDWFlags, vDWFlagsLen) then begin
aErrorMsg := 'Internal error in SetToIgnoreCerticateErrors when trying to set wininet INTERNET_OPTION_SECURITY_FLAGS flag .' + GetWininetError;
Exit;
end;
Result := True;
except
on E: Exception do begin
aErrorMsg := 'Unknown error in SetToIgnoreCerticateErrors.' + E.Message;
end;
end;
end;
vErrorNone := HttpSendRequest(HttpOpen_Request, nil, 0, nil, 0);
if vErrorNone = False then
begin
vErrorID := GetLastError;
if (vErrorID = ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED) then
begin
//call SetToIgnoreCerticateErrors
//re-send the request
end
end
end;
我从wininet API中提取了SetToIgnoreCerticateErrors
,但可能无法准确编译它。
这些是步骤:
1 - 得到错误
2 - 检查错误是否是证书错误
3 - 如果是证书错误,他们就像我一样调用InternetSetOption
4 - 重新发送请求。
我不知道如何实现第一个选项“向用户显示证书错误,让他决定是否继续。”因为我从来没有这样做过。
另外,请检查一下:How To Handle Invalid Certificate Authority Error with WinInet
我希望它可以帮到你。