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

NestJS拦截器执行redirect报Cannot set headers after they are sent错误

问题场景

请求路径为 /login/login.html,需要重定向至 /login,因此在自定义UricheckInterceptor拦截器中编写重定向判断逻辑,拦截器代码如下:

export class UricheckInterceptor implements NestInterceptor {
    constructor(private uri: string[]) {}
    intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
        const response = context.switchToHttp().getResponse();
        const request = context.switchToHttp().getRequest();
        const { pathname } = parseurl(request);
        const pathLength = pathname.length;
        const pathSlash = pathname.lastIndexOf('/');
        const pathLast = pathname.substring(pathSlash + 1, pathLength);
        const queryString = request.query;
        if (pathLast === this.uri[1]) {
            if (Object.keys(queryString).length > 0) {
                if (queryString.code !== undefined && queryString.bst !== undefined) {
                    response.redirect(301, `./${this.uri[0]}?code=${queryString.code}&bst=${queryString.bst}`);
                    next.handle();
                } 
        } else {
            return next.handle();
        }
    }
}
问题现象

重定向逻辑触发后,服务端抛出未捕获的Promise错误,错误信息如下:

This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason:
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client....
问题诉求

经多次尝试无法定位问题根源,需要确认代码中存在的错误点。

错误点定位

代码存在3个核心问题,直接导致报头重复发送的错误:

  • 重定向后未终止请求流程:执行response.redirect(301, xxx)时,服务端已经向客户端发送了完整的301响应报头,后续再调用next.handle()会让请求继续流转到后续的拦截器、控制器逻辑,尝试再次向客户端写入响应报头,直接触发ERR_HTTP_HEADERS_SENT错误。
  • 判断分支存在逻辑漏洞:当前if嵌套逻辑存在覆盖缺口,当pathLast === this.uri[1]但query参数为空、或者缺少code/bst参数时,拦截器既没有返回响应,也没有放行请求,会导致请求悬挂或执行逻辑异常。
  • 重定向路径存在隐患:使用相对路径./拼接重定向地址,在多层路径场景下容易出现路径拼接错误,直接使用绝对路径更稳定。
修复后参考代码
export class UricheckInterceptor implements NestInterceptor {
    constructor(private uri: string[]) {}
    intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
        const response = context.switchToHttp().getResponse();
        const request = context.switchToHttp().getRequest();
        const { pathname } = parseurl(request);
        const pathSlash = pathname.lastIndexOf('/');
        const pathLast = pathname.substring(pathSlash + 1, pathname.length);
        const queryString = request.query;
        
        if (pathLast === this.uri[1]) {
            // 直接校验必填参数,无需先判断query对象长度
            if (queryString.code !== undefined && queryString.bst !== undefined) {
                // 发送重定向响应后直接return,不再执行后续逻辑
                response.redirect(301, `/${this.uri[0]}?code=${queryString.code}&bst=${queryString.bst}`);
                return;
            }
        }
        // 所有不满足重定向条件的请求统一放行
        return next.handle();
    }
}

内容的提问来源于stack exchange,提问作者Curtis

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 22:18:04