【问题标题】:NestJs redirect without response usageNestJs 重定向而不使用响应
【发布时间】:2019-01-15 20:56:52
【问题描述】:

是否可以在不使用 Response 对象的情况下从 Nest 控制器进行重定向?

目前我知道我们只能通过将Response 对象直接注入到路由处理程序中来做到这一点。

【问题讨论】:

  • 您能否添加代码,说明您如何使用 Response 对象处理重定向?
  • @KimKern,这是常见的。 res.redirect(someVal)。没什么特别的。
  • 请问使用@Res有什么问题?如果您只是出于好奇而询问,那么我可以告诉您,除了使用 res.redirect
  • @VinceOPS,主要是禁用嵌套的默认处理。但是,这里很好,它不会破坏任何关键任务。我可以继续使用res.redirect
  • 在测试控制器时非常有用。模拟整个响应对象是很烦人的......

标签: javascript node.js nestjs


【解决方案1】:

你可以写一个RedirectInterceptor

@Injectable()
export class RedirectInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, stream$: Observable<any>): Observable<any> {
    const response = context.switchToHttp().getResponse();
    response.redirect('redirect-target');
    return stream$;
  }
}

然后像这样在你的控制器中使用它:

@Get('user')
@UseInterceptors(RedirectInterceptor)
getUser() {
  // will be redirected.
}

请务必不要从控制器返回任何内容,否则您将收到以下错误:Can't set headers after they are sent.

如果需要,RedirectInterceptor 也可以是动态的:

@Injectable()
export class RedirectInterceptor implements NestInterceptor {
  constructor(private readonly target: string) {}
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

  intercept(context: ExecutionContext, stream$: Observable<any>): Observable<any> {
    const response = context.switchToHttp().getResponse();
    response.redirect(this.target);
                      ^^^^^^^^^^^
    return stream$;
  }
}

然后在控制器中:

@UseInterceptors(new RedirectInterceptor('redirect-target'))

【讨论】:

    【解决方案2】:

    我做得比较复杂,但我认为它已经足够好了。

    1. 像这样创建 util/RedirectException 类:

    如下代码:

    import { HttpException, HttpStatus } from '@nestjs/common';
    
    export class RedirectException extends HttpException {
      constructor(message?: string | object) {
        super(message, HttpStatus.CONTINUE);
      }
    }
    
    1. 通过:nest g f RedirectFilter 创建RedirectFilter

    这样写代码:

    import { ArgumentsHost, Catch, ExceptionFilter, HttpException, HttpStatus } from '@nestjs/common';
    import { RedirectException } from './util/redirect-exception';
    
    @Catch()
    export class RedirectFilter implements ExceptionFilter {
     catch(exception: any, host: ArgumentsHost) {
      const res = host.switchToHttp().getResponse(),
      req = host.switchToHttp().getRequest();
      try {
        if (exception instanceof RedirectException) {
          Object.keys(exception.message).forEach(k => {
            req.session[k] = exception.message[k];
          });
          req.session.save(() => {
            res.redirect(exception.message.url);
          });
          return;
        }
    
        if (exception instanceof HttpException) {
          return res.status(exception.status).json(exception.message)
        }
        res.status(500).json({status: 500, message: 'Internal Server error'})
       } catch (e) {
        return res.status(500)
          .json({
            status: HttpStatus.INTERNAL_SERVER_ERROR,
            message: e.message
          });
       }
      }
    }
    

    这个类帮助你处理抛出异常时的所有响应。是的,这包括重定向异常。现在我们可以用精确的参数抛出异常,它可以工作了!

    1. 使用main.ts中的过滤器:app.useGlobalFilters(new RedirectFilter());

    2. 在控制器中,如果你想重定向到一个 url,你可以随时这样做

    代码:

     throw new RedirectException({
        url: 'the url you want to redirect',
        field1: 'The first field you want to pass to session'
        field2: 'The second field you want to pass to session'
     });
    
    1. 如果您想在重定向时按会话传递数据,请不要忘记设置 express-session:https://www.npmjs.com/package/express-session

    如果你不想使用它,只需将if (exception instanceof RedirectException) {} 中的代码替换为:res.redirect(exception.message.url);。它不再检查和设置会话。

    【讨论】:

    • 其实这不是最好的方式,因为你在这里使用异常来进行流控制,这应该以正常的代码执行方式来完成。有很多资源描述了为什么通过异常抛出来执行流控制任务是不好的。
    • 我知道这不是最好的方法。但这是我能想到的唯一方法。问题是:当我想在“if”语句中重定向到另一个 URL 时,我该怎么办。然后让方法“返回”?如果您返回,事情将类似于#2 评论。忘记“if else”或“else”语句。我已经很多年没有使用它们了。有时,我的伙伴会写return res.redirect('/'),然后让服务器崩溃,然后……我编写代码来避免他们这样做。避免尽可能多的事情会使 nodejs 服务器崩溃!
    【解决方案3】:

    (与这里的另一个答案有点不同的实现......)

    我创建了一个RedirectError,它可以比装饰器更动态地抛出

    import { ExceptionFilter, Catch, ArgumentsHost } from '@nestjs/common';
    import { Response } from 'express';
    
    export class RedirectError extends Error {
      constructor(public readonly status: number, public readonly url: string) {
        super();
      }
    }
    
    @Catch(RedirectError)
    export class RedirectFilter implements ExceptionFilter {
      public catch(exception: RedirectError, host: ArgumentsHost) {
        const ctx = host.switchToHttp();
        const response = ctx.getResponse<Response>();
        return response.redirect(exception.status, exception.url);
      }
    }
    

    然后在main.ts 中设置它:

      app.useGlobalFilters(new RedirectFilter());
    

    最后使用它:

    throw new RedirectError(302, '/some-target');
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-12
      • 1970-01-01
      • 2013-09-10
      • 1970-01-01
      相关资源
      最近更新 更多