不能将 @Res() 与 FilesInterceptor() 一起使用

Posted

技术标签:

【中文标题】不能将 @Res() 与 FilesInterceptor() 一起使用【英文标题】:Can't use @Res() with FilesInterceptor() 【发布时间】:2019-09-01 17:46:16 【问题描述】:

我正在尝试使用内置 multer 上传文件,然后将响应发送回用户以确认成功或失败。直到今天一切都很好,当我尝试上传响应时不会出现。经过一番挖掘,我发现当我将@res 与@UploadedFile 一起使用时,它不会执行控制器。我是 Nest.js 的新手。

工作。

@Post('uploads/avatar')
async uploadFile(@Req() req, @UploadedFile() avatar) 
  console.log(req.body);
  if (!req.body.user_id) 
    throw new Error('id params not found.');
  
  try 
    const resultUpload = await this.userService.uploadUserImage(
      req.body.user_id,
      avatar, 
    ); // returns the url for the uploaded image
    return resultUpload;
   catch (error) 
    console.log(error);
    return error;
  

不工作。

@Post('uploads/avatar')
async uploadFile(@Req() req, @UploadedFile() avatar, @Res() res) 
  console.log(req.body);
  if (!req.body.user_id) 
    throw new Error('id params not found.');
  
  try 
    const resultUpload = await this.userService.uploadUserImage(
      req.body.user_id,
      avatar,      
    ); // returns the url for the uploaded image
    return resultUpload;
   res.send(resultUpload);
   catch (error) 
    console.log(error);
    res.send(error);
  

【问题讨论】:

【参考方案1】:

看,当您使用拦截器时,您正在处理(使用.handle())响应流(observable)而不是它的整个包,但是使用 express @987654324 @ 实际上以某种方式绕过了响应流的整个流程。

nestjs official documents 中也明确提到了这一点:

我们已经知道 handle() 返回一个 Observable。溪流 包含从路由处理程序返回的值,因此我们可以 使用 RxJS 的 map() 运算符轻松地对其进行变异。

警告

响应映射功能不适用于 特定于库的响应策略(直接使用 @Res() 对象 被禁止)。

【讨论】:

【参考方案2】:

在嵌套中,您应该始终避免注入 @Res,因为那样您会丢失很多使嵌套如此出色的东西:拦截器、异常过滤器......

实际上,在大多数情况下,您不需要@Res,因为nest 会自动处理正确发送响应。

如果你想从控制器方法发送数据,你可以直接返回数据(PromisesObservables 也会被自动解析)。如果要向客户端发送错误,只需抛出相应的HttpException,例如404 -> NotFoundException:

@Post('uploads/avatar')
async uploadFile(@Req() req, @UploadedFile() avatar) 
  if (!req.body.user_id) 
    // throw a 400
    throw new BadRequestException('id params not found.');
  
  try 
    const resultUpload = await this.userService.uploadUserImage(
      req.body.user_id,
      avatar, 
    );
    return resultUpload;
   catch (error) 
    if (error.code === 'image_already_exists') 
      // throw a 409
      throw new ConflictException('image has already been uploaded');
     else 
      // throw a 500
      throw new InternalServerException();
    
  

如果由于某种原因必须在此处注入@Res,则不能使用FilesInterceptor。然后你必须自己配置multer中间件。


旁注

您可以创建一个自定义装饰器来访问userId

import  createParamDecorator  from '@nestjs/common';

export const UserId = createParamDecorator((data, req) => 
  if (!req.body || !req.body.user_id) 
    throw new BadRequestException('No user id given.')
  
  return req.body.user_id;
);

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

@Post('uploads/avatar')
async uploadFile(@UserId() userId, @UploadedFile() avatar) 

【讨论】:

我对这个概念有疑问,但这一切都消除了。非常感谢。 您有什么疑问?嵌套的一大优点是您不必直接处理响应对象,而是可以使用框架提供的更高级别的抽象。 我正在开发一个api。我在大多数控制器中都使用了@Res,但是当我使用@UploadedFile() 进行尝试时,我没有工作。我怀疑这是因为他们在框架中实现的 multer。 我如何使用自动发送响应返回一个 json 对象? status: "OK", mesage: "Successful" 只要返回一个javascript对象,它就会自动序列化为JSON。

以上是关于不能将 @Res() 与 FilesInterceptor() 一起使用的主要内容,如果未能解决你的问题,请参考以下文章

TS不能将类型“any[]”分配给类型“never[]”

res/raw与assets目录的区别

R 绘图 ggplot png 所支持的最大图片背景与res的关系

将一个函数的输出插入另一个函数

Android复制res/raw目录的文件到SD卡下

Android复制res/raw目录的文件到SD卡下