如何让THorse中间件返回401后终止控制器执行?
THorse框架授权中间件:返回401后控制器仍执行的解决方法
在Delphi 12 CE中基于THorse框架搭建API时,配置授权中间件后遇到问题:当中间件返回401未授权状态后,目标控制器仍会执行。测试发送带无效Token的/echo请求时,会同时收到401响应和端点返回结果;尝试抛出EHorseException虽能终止执行,但返回的是完整HTML页面而非JSON格式响应。
相关代码片段
项目启动代码(简化版)
begin dmMain := TdmMain.Create(nil); TTokenStore.Initialize; // Activate JSON middleware THorse //.Use(Jhonson()) .Use(AuthMiddleware); RegisterAuthorizationRoutes; TMainController.RegisterRoutes; Writeln('Horse MVC server running on http://localhost:9000/'); THorse.Listen(9000); TTokenStore.Finalize; end.
授权中间件代码
uses Horse, System.SysUtils, TokenStore, Winapi.ActiveX, Horse.Exception, Horse.Commons; procedure AuthMiddleware(Req: THorseRequest; Res: THorseResponse; Next: TProc); implementation threadvar ComInitialized: Boolean; procedure EnsureCOMInitialized; begin if not ComInitialized then begin CoInitialize(nil); // <<< STA, verplicht voor ADO ComInitialized := True; end; end; procedure AuthMiddleware(Req: THorseRequest; Res: THorseResponse; Next: TProc); var Header, Token : string; Authenticated, Authorized: Boolean; E: EHorseException; begin EnsureCOMInitialized; // Skip login route if Req.PathInfo = '/auth/login' then begin Next(); end else begin Header := Req.Headers['Authorization']; if Header.StartsWith('Bearer ') then Token := Header.Substring(7) else Token := ''; Authenticated := (Token <> '') and TTokenStore.ValidateToken(Token); if not Authenticated then begin Res.Status(401).Send('Unauthorized'); // token ontbreekt of ongeldig end else Next(); // alles ok, doorgaan naar route handler end; end;
测试端点代码
interface procedure RegisterEchoRoutes; implementation uses System.JSON, Horse, Horse.Jhonson; procedure RegisterEchoRoutes; begin THorse.Post('/echo', procedure(Req: THorseRequest; Res: THorseResponse; Next: TProc) var BodyJSON: TJSONObject; begin BodyJSON := TJSONObject.ParseJSONValue(Req.Body) as TJSONObject; try Res .ContentType('application/json') .Send(BodyJSON.ToJSON); finally BodyJSON.Free; end; end ); end;
正确处理方式
问题核心是:THorse中间件仅设置响应状态和内容不会自动终止后续流程,必须显式中断执行。以下两种方案可解决:
方案一:设置响应后直接退出中间件
修改中间件中未授权分支的代码,添加Exit终止后续流程,同时指定JSON响应格式:
if not Authenticated then begin Res.Status(401) .ContentType('application/json') .Send('{"error":"Unauthorized"}'); Exit; // 直接退出,不调用Next,阻止后续控制器执行 end else Next();
方案二:自定义异常+全局异常中间件
适合统一管理所有API的异常响应格式:
- 定义自定义授权异常
type EHorseUnauthorized = class(EHorseException) public constructor Create; reintroduce; end; constructor EHorseUnauthorized.Create; begin inherited Create('Unauthorized'); Status(THTTPStatus.Unauthorized); end;
- 修改中间件抛出异常
if not Authenticated then begin raise EHorseUnauthorized.Create; end else Next();
- 添加全局异常处理中间件
procedure ExceptionMiddleware(Req: THorseRequest; Res: THorseResponse; Next: TProc); begin try Next; except on E: EHorseException do begin Res.Status(E.StatusCode) .ContentType('application/json') .Send(Format('{"error":"%s"}', [E.Message])); end; end; end; // 注册中间件时注意顺序,异常中间件要放在授权中间件之前 THorse .Use(ExceptionMiddleware) .Use(AuthMiddleware);
内容的提问来源于stack exchange,提问作者GuidoG
相关产品推荐
相关产品推荐

