我正在使用Delphi XE 6和TIdHttp组件(Indy 10.6.0.5122)并试图通过http代理(CCProxy - http://www.webservicex.net/globalweather.asmx)使用SOAP服务 - http://www.youngzsoft.net/ccproxy/。问题是,在第一次尝试连接到Web服务时,我收到了“未经授权”的响应:
<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head><body><h1>Unauthorized ...</h1>
<h2>IP Address: xxx.xxx.xxx.:61295<br>
MAC Address: <br>
Server Time: 2014-11-18 14:19:00<br>
Auth Result: </h2></body></html>
我已将IdSSLIOHandlerSocketOpenSSL和IdLogDebug1组件链接到IdHttp以调试问题。
执行的操作日志
***********************IdSSLIOHandlerSocketOpenSSL1Status
Connecting to xxx.xxx.xxx.xxx.
***********************IdLogDebug1Send
POST http://www.webservicex.net/globalweather.asmx HTTP/1.1
Content-Type: text/xml; charset=utf-8
Content-Length: 388
SOAPAction: http://www.webserviceX.NET/GetCitiesByCountry
Host: www.webservicex.net
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding: identity
User-Agent: Mozilla/3.0 (compatible; Indy Library)
***********************IdLogDebug1Send
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<GetCitiesByCountry xmlns="http://www.webserviceX.NET">
<CountryName>Romania</CountryName>
</GetCitiesByCountry>
</soap:Body>
</soap:Envelope>
***********************IdLogDebug1Receive
HTTP/1.0 407 Unauthorized
Server: Proxy
Proxy-Authenticate: Basic realm="CCProxy Authorization"
Cache-control: no-cache
<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head><body><h1>Unauthorized ...</h1>
<h2>IP Address: xxx.xxx.xxx.xxx:61295<br>
MAC Address: <br>
Server Time: 2014-11-18 14:19:00<br>
Auth Result: </h2></body></html>
***********************IdSSLIOHandlerSocketOpenSSL1Status
Disconnected.
现在,有趣的是,如果我再次尝试调用Web服务,一切正常。记录操作:
***********************IdSSLIOHandlerSocketOpenSSL1Status
Connecting to xxx.xxx.xxx.xxx.
***********************IdLogDebug1Send
POST http://www.webservicex.net/globalweather.asmx HTTP/1.1
Content-Type: text/xml; charset=utf-8
Content-Length: 388
SOAPAction: http://www.webserviceX.NET/GetCitiesByCountry
Host: www.webservicex.net
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding: identity
User-Agent: Mozilla/3.0 (compatible; Indy Library)
Proxy-Authorization: Basic YW1ibzphbWJvIQ==
***********************IdLogDebug1Send
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<GetCitiesByCountry xmlns="http://www.webserviceX.NET">
<CountryName>Romania</CountryName>
</GetCitiesByCountry>
</soap:Body>
</soap:Envelope>
***********************IdLogDebug1Receive
HTTP/1.1 200 OK
Cache-Control: private, max-age=0
Content-Length: 2456
***********************IdLogDebug1Receive
Content-Type: text/xml; charset=utf-8
Server: Microsoft-IIS/7.0
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Tue, 18 Nov 2014 12:26:21 GMT
<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><GetCitiesByCountryResponse xmlns="http://www.webserviceX.NET"><GetCitiesByCountryResult><NewDataSet>
<Table>
<Country>Romania</Country>
<City>Arad</City>
</Table>
<Table>
<Country>Romania</Country>
<City>Bacau</City>
</Table>
......
回应是正确的。
申请代码
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, IdBaseComponent,
IdComponent, IdTCPConnection, IdTCPClient, IdHTTP, Soap.SOAPHTTPTrans,
IdAuthentication, IdHeaderList, IdIntercept, IdLogBase, IdLogDebug,
IdIOHandler, IdIOHandlerSocket, IdIOHandlerStack, IdSSL, IdSSLOpenSSL
,IdGlobal;
type
TForm1 = class(TForm)
IdHTTP1: TIdHTTP;
Button1: TButton;
HTTPReqResp1: THTTPReqResp;
Memo1: TMemo;
Button2: TButton;
Button3: TButton;
Button4: TButton;
IdSSLIOHandlerSocketOpenSSL1: TIdSSLIOHandlerSocketOpenSSL;
IdLogDebug1: TIdLogDebug;
Memo2: TMemo;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure IdHTTP1ProxyAuthorization(Sender: TObject;
Authentication: TIdAuthentication; var Handled: Boolean);
procedure IdSSLIOHandlerSocketOpenSSL1StatusInfo(const AMsg: string);
procedure IdSSLIOHandlerSocketOpenSSL1Status(ASender: TObject;
const AStatus: TIdStatus; const AStatusText: string);
procedure IdLogDebug1Receive(ASender: TIdConnectionIntercept;
var ABuffer: TIdBytes);
procedure IdLogDebug1Send(ASender: TIdConnectionIntercept;
var ABuffer: TIdBytes);
procedure IdHTTP1Authorization(Sender: TObject;
Authentication: TIdAuthentication; var Handled: Boolean);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
postData: TMemoryStream;
begin
postData := TMemoryStream.Create;
try
Memo1.Lines.Clear;
postData.LoadFromFile('..\..\soap1.1.txt');
IdHTTP1.Request.ContentType := 'text/xml';
IdHTTP1.Request.Charset := 'utf-8';
IdHTTP1.Request.CustomHeaders.Values['SOAPAction'] := 'http://www.webserviceX.NET/GetCitiesByCountry';
IdHTTP1.ProtocolVersion := pv1_1;
IdHTTP1.HTTPOptions := IdHTTP1.HTTPOptions + [hoKeepOrigProtocol];
Memo1.Lines.Text := IdHTTP1.Post('http://www.webservicex.net/globalweather.asmx', postData);
finally
postData.Free;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
with IdHTTP1.ProxyParams do
begin
ProxyServer := 'xxx.xxx.xxx.xxx';
ProxyPort := 808;
ProxyUsername := 'User-001';
ProxyPassword := 'User-001!';
end;
end;
procedure TForm1.IdHTTP1Authorization(Sender: TObject;
Authentication: TIdAuthentication; var Handled: Boolean);
begin
//
Authentication.Username := 'User-001';
Authentication.Password := 'User-001!';
end;
procedure TForm1.IdHTTP1ProxyAuthorization(Sender: TObject;
Authentication: TIdAuthentication; var Handled: Boolean);
begin
//
// Authentication.Username := 'User-001';
// Authentication.Password := 'User-001!';
// Handled := true;
end;
procedure TForm1.IdLogDebug1Receive(ASender: TIdConnectionIntercept;
var ABuffer: TIdBytes);
begin
Memo2.Lines.Add(#13#10+'***********************IdLogDebug1Receive '+#13#10+BytesToString(ABuffer))
end;
procedure TForm1.IdLogDebug1Send(ASender: TIdConnectionIntercept;
var ABuffer: TIdBytes);
begin
Memo2.Lines.Add(#13#10+'***********************IdLogDebug1Send '+#13#10+BytesToString(ABuffer))
end;
procedure TForm1.IdSSLIOHandlerSocketOpenSSL1Status(ASender: TObject;
const AStatus: TIdStatus; const AStatusText: string);
begin
Memo2.Lines.Add(#13#10+'***********************IdSSLIOHandlerSocketOpenSSL1Status '+#13#10+AStatusText)
end;
procedure TForm1.IdSSLIOHandlerSocketOpenSSL1StatusInfo(const AMsg: string);
begin
Memo2.Lines.Add(#13#10+'***********************IdSSLIOHandlerSocketOpenSSL1StatusInfo '+#13#10+AMsg)
end;
end.
我应该如何进行身份验证才能在第一次尝试时使用?
PS:我已经读过这个问题了 - Authorization failure TIdHTTP over HTTPS。
答案:根据Remy Lebeau的指示,问题通过设置来解决OnProxySelectAuthorization
事件并将 hoInProcessAuth 添加到
IdHTTP1.HTTPOptions
答案 0 :(得分:2)
确保您已将IdAuthentication
单元添加到uses
子句中,以便TIdHTTP
可以在407回复中处理Proxy-Authorization
标题,并确保您拥有TIdHTTP.OnProxyAuthorization
{1}}已分配事件处理程序(即使它只返回Handled:=True
),否则TIdHTTP
在处理407回复时不会尝试代理授权,即使您在{{1}中提供了用户名/密码属性。
最有可能发生的事情是TIdHTTP.ProxyParams
属性在第一次请求期间最初为零,并在处理407回复时填入TIdHTTP.ProxyParams.Authentication
对象,但缺少TIdBasicAuthentication
事件处理程序导致OnProxyAuthorization
跳过授权,然后在发出第二个请求时TIdHTTP
属性不再为nil,因此它在那时尝试授权。
如果未分配TIdHTTP.ProxyParams.Authentication
事件,则跳过代理授权似乎是一个错误,恕我直言。相比之下,只要为TIdHTTP.OnProxyAuthorization
属性分配了非空值,就可以取消分配TIdHTTP.OnAuthorization
事件。我现在更新了TIdHTTP.Request.Password
,其TIdHTTP
属性的OnProxyAuthorization
事件的逻辑类似。
因此,要么更新到最新的SVN快照,要么只是分配一个TIdHTTP.ProxyParams.Password
事件处理程序,那么你应该没问题:
TIdHTTP.OnProxyAuthorization