我在Delphi XE中创建了一个SOAPServerwithINDYVCL。当客户端由于客户端超时或网络连接丢失等原因而与服务器断开连接时。 我在服务器端收到错误,因为Socket Error 10053 - 软件导致连接中止。
此错误弹出并阻止我的服务器线程。
我还通过SOAPDMServerIndy的演示检查了这一点。在这里,如果我启动服务器,连接客户端,在服务器响应之前断开客户端我得到套接字错误。
任何人都知道如何处理此异常?
答案 0 :(得分:0)
即使在这个时候,这个问题仍然存在。因为此代码:
procedure TWebRequestHandler.HandleException(Sender: TObject);
var
Handled: Boolean;
Intf: IWebExceptionHandler;
begin
Handled := False;
if ExceptObject is Exception and
Supports(Sender, IWebExceptionHandler, Intf) then
try
Intf.HandleException(Exception(ExceptObject), Handled);
except
Handled := True;
System.SysUtils.ShowException(ExceptObject, ExceptAddr);
end;
if (not Handled) then
System.SysUtils.ShowException(ExceptObject, ExceptAddr);
end;
第Intf.HandleException(Exception(ExceptObject), Handled)
行调用TCustomWebDispatcher.HandleException过程。此过程检查应用程序的TWebModule子代中是否存在OnException事件处理程序。如果存在(我建议这样做),则将var参数'Handled'设置为true来调用事件处理程序过程。
procedure TCustomWebDispatcher.HandleException(E: Exception; var Handled: Boolean);
begin
Handled := False;
if Assigned(FOnException) then
begin
Handled := True;
if Response <> nil then
Response.StatusCode := 500; { Allow the user to override the StatusCode }
FOnException(Self, E, Handled);
if Handled and (Response <> nil) then
Response.SendResponse;
end;
if not Handled then
if Response <> nil then
begin
Response.Content := Format(sInternalApplicationError, [E.Message, Request.PathInfo]);
if not Response.Sent then
begin
Response.StatusCode := 500;
Response.SendResponse;
end;
Handled := True;
end;
end;
处理程序返回时有两种情况:
处理为真;将发送导致新异常的响应。这将被传播回调用代码(第一个块中的过程),因此将调用ShowException。
Handled为False; Response <> nil
的计算结果为True,因此当Response.Sent
为False时,将会发生相同的事情。
我通过尝试从OnException事件处理程序发送响应来解决此问题。如果失败,则会引发异常。在那种情况下,我会将TWebModule的后代的只读属性“ Response”的“ FResponse”字段设置为“ nil”。但是,此字段是私有字段,因此我使用了一些rtti来访问它。
procedure TwbmWebBrokerServerModule.UnlinkResponseObject;
begin
inherited;
TRTTIContext.Create.GetType(ClassInfo).GetField('FResponse').SetValue(Self, TValue.From(nil));
end;
procedure TwbmWebBrokerServerModule.WebModuleException(Sender: TObject; E: Exception; var Handled: Boolean);
begin
uVMI_Tools.AppendToLog(E.Message + ' (' + Request.PathInfo + ')');
if Request.Accept.Contains(CONTENTTYPE_APPLICATION_JSON) then
begin
Response.Content := StringToJSON(E.Message);
Response.ContentType := CONTENTTYPE_APPLICATION_JSON;
end
else
Response.Content := E.Message;
try
Response.SendResponse;
except
UnlinkResponseObject;
end;
end;
因此,当发送响应时发生异常时,属性“ Response”设置为nil,因此不会尝试再次发送响应。
不需要破坏响应对象,将nil设置为足够。这是因为Response对象是在TIdCustomHTTPServer类中创建的,该类刚刚将其传递给TWebModule子孙。 (实际上是TWebModule的父类TCustomWebDispatcher)