我在 Delphi XE 中创建了一个 SOAPServerwithINDYVCL。当客户端由于客户端超时或网络连接断开等任何原因与服务器断开连接时。我在服务器端收到错误,因为 Socket Error 10053 - 软件导致连接中止。
弹出此错误并阻止我的服务器线程。
我还用 SOAPDMServerIndy 的演示检查了这一点。在这里,如果我启动服务器,连接客户端并且在服务器响应之前断开客户端,我会收到套接字错误。
任何人都知道如何处理这个异常?
即使在这个时候,这个问题仍然存在。这是因为这段代码:
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。
处理为假;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;
因此,当发送响应时发生异常时,属性“响应”设置为 nil,因此不会尝试再次发送响应。
不需要销毁响应对象,将 nil 分配给它就足够了。这是因为 Response 对象是在 TIdCustomHTTPServer 类中创建的,该类刚刚将其传递给 TWebModule 后代。(其实是TWebModule的父类TCustomWebDispatcher)