nestjs 如何优雅地给 response 设置 header?

2020-11-15 19:28:10 +08:00
 rikka

很常见的需求:一个登录请求过来后验证通过后要给 response 的 header 设置 token

我找到了 2 种方法但都不满意不优雅

方法一

按照文档来

@Post('login')
async login (@Body() param,@Res res) {
 const data={}
  res.set('token','')//这里设置 response 没问题
  //但是啊下面的 return 就无效了!!
  //你必须自己手动操作 res.json().send()去给客户端返回数据
  //还有副作用是拦截器不正常了
 return {data}
}

很难受,这种方法太怪胎了,还有副作用,弃之

方法二

用拦截器来帮忙设置 header

Injectable()
export class SetTokenInterceptor implements NestInterceptor {
  intercept (context: ExecutionContext, next: CallHandler): Observable<any> {
    return next.handle().pipe(tap(result => {
      if (result?.token) {
        const http = context.switchToHttp()
        const res = http.getResponse()
        res.set('token', result.token)
        delete result.token
        //这里要删掉 token,因为我不希望 token 返回到 respoonse 的 body 中
      }
    }))
  }
}
@Post('login')
@UseInterceptors(SetTokenInterceptor)
async login (@Body() param) {
 const data={}
 return {data,token:''}
 //问题在于怎么把 token 传给拦截器?
 //只能带在返回数据里,然后拦截器拿到 token 再删掉
}

这种方法也很难受,说不上具体,总之就是非常难受

所以还有其他方法吗

7193 次点击
所在节点    Node.js
31 条回复
zengming00
2020-11-15 19:34:56 +08:00
老老实实用 express/koa,这风格一看就是 java 抄过来的,为什么要用 java 那套东西来复杂化 node.js
rikka
2020-11-15 19:37:31 +08:00
@zengming00 #1 我在这里被众人安利 nestjs 😂
gouflv
2020-11-15 21:50:49 +08:00
token 直接放 json 返回咯
luob
2020-11-15 22:21:19 +08:00
在后端给 response header 设置 token 没有任何意义

供参考:

@Post('login')
async login (@Body() param,@Res res) {
const {username, password} = param
const token =this.authService.validateUser(username, password)
return { token }
}

@Get('/profile')
@UserRequired()
async user (@CurrentUser() user) {
return this.userService.getUser(user.id)
}

实现一下 @UserRequired()和 @CurrentUser()这两个注解即可
rikka
2020-11-15 22:32:30 +08:00
@luob #4 怎么会没意义呢,我鉴权用 jwt 来做,就想 token 放在 response header 中给客户端去拿,极其常见的情况

另外你第一段代码试过了吗,你一旦用 @Res 这个装饰器后面 return 就没用了
luob
2020-11-15 22:56:53 +08:00
@rikka 那里是忘了删除,显然不需要 @Req

大家都是
客户端从 body 里拿到 token 保存到状态然后把 token 塞进每个请求里
你为什么要
客户端从 header 里挖 token 保存到状态然后把 token 塞进每个请求里


你自己造了个 token/set-token 方案?你都这样玩了为什么不用 set-cookie 呢?
rikka
2020-11-15 23:02:35 +08:00
@luob #6

我也没啥特别的啊
仅仅仅就想 token 放 header 里面给客户端拿而已
为什么呢?因为客户端请求的时候会把 token 放在 header,所以为了对称美(狗头),下发 token 也想放 header 里面
rikka
2020-11-15 23:05:35 +08:00
@luob #6 还有个好处忘了讲,比方 token 还剩 10 分种就过期了,客户端做其他业务请求的时候我想重新下发一个新 token 给他啊,放 header 里面就就非常合适
rikka
2020-11-15 23:13:46 +08:00
业务交互数据放 body
鉴权这种相对特殊的数据放 header

难道不是更常见?
rikka
2020-11-15 23:43:33 +08:00
@luob #6 卧槽,还在想怎么实现这个 @CurrentUser,然后就受到启发,我可以自己写个装饰器自己拿到 response 啊

```
export const resp = createParamDecorator((data, ctx: ExecutionContext) => {
return ctx.switchToHttp().getResponse()
})

@Post('login')
async login (@Body() param,@resp() resp:any) {
const data={}
resp.set('token','')
return {data}
}
```

非常非常完美!!!
zy445566
2020-11-16 10:21:32 +08:00
10L 这样不也一样有副作用,要想最没副作用,那就这个方法就单独做参数处理器,return 出来后,用一个出口方法了 merge 到 resp 上,这样副作用才最小
namelosw
2020-11-16 11:19:12 +08:00
Nest 的设计就不是无副作用的
rikka
2020-11-16 14:11:48 +08:00
@zy445566 #11 我说的副作用是指:只要用了 nestjs 提供的 @Res 装饰器后就不能直接 return 数据了,必须操作 res.json/send 去返回数据,然后这又导致拦截器不能正常工作

你说副作用具体是什么,还是说是指函数式编程中的那种副作用啊
zy445566
2020-11-16 14:21:36 +08:00
@rikka 嗯,我以为你说的是函数式编程的副作用
gxm44
2020-11-16 16:23:55 +08:00
@zengming00 赞同
Kasumi20
2020-11-20 22:19:51 +08:00
你用了 @Res 注解就会被忽略返回值啊, 这样避免重复操作流....
res.send 不就好了? 非要 return ...
rikka
2020-11-20 22:25:24 +08:00
@Kasumi20 #16 我所有的控制器方法都是直接 return 数据,唯独这里不能 return,代码看起来我那个难受啊。。。
hongweiliuruige
2020-11-24 18:44:55 +08:00
写个装饰器,装饰器可以拿到 req res,res 里设置下就行了,例如 @SetToken(),,然后装饰器里面写逻辑,token 从哪里来
hongweiliuruige
2020-11-24 18:59:52 +08:00
```javascript
export const SetCookie = createParamDecorator(
(data: unknown, ctx: ExecutionContext) => {
const response: Response = ctx.switchToHttp().getResponse();
return function(data){
response.cookie('auth',data);
}
},
);
```
参考
BoringTu
2020-11-25 11:46:06 +08:00
@rikka 你这所谓“对称美”本来就是不应该的啊,我是有强迫症的人,我都不会这么考虑,因为不应该

登录接口响应的 token 是作为响应数据存在的,理应放在 body 里
需要鉴权的接口请求的 token 是作为鉴权依据存在的,理应放在 header 里

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/725512

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX