You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让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的异常响应格式:

  1. 定义自定义授权异常
type
  EHorseUnauthorized = class(EHorseException)
  public
    constructor Create; reintroduce;
  end;

constructor EHorseUnauthorized.Create;
begin
  inherited Create('Unauthorized');
  Status(THTTPStatus.Unauthorized);
end;
  1. 修改中间件抛出异常
if not Authenticated then
begin
  raise EHorseUnauthorized.Create;
end
else
  Next();
  1. 添加全局异常处理中间件
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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.11 19:13:09