NestJS响应处理 #

响应处理概述 #

NestJS支持两种响应处理方式:

  1. 标准模式:返回数据,由框架自动序列化
  2. Express模式:使用@Res()直接操作响应对象

标准响应 #

自动序列化 #

typescript
import { Controller, Get } from '@nestjs/common';

@Controller('users')
export class UsersController {
  @Get()
  findAll() {
    return {
      message: 'Success',
      data: [
        { id: 1, name: 'John' },
        { id: 2, name: 'Jane' },
      ],
    };
  }
}

响应:

json
{
  "message": "Success",
  "data": [
    { "id": 1, "name": "John" },
    { "id": 2, "name": "Jane" }
  ]
}

异步响应 #

typescript
@Get()
async findAll() {
  const users = await this.usersService.findAll();
  return users;
}

RxJS Observable #

typescript
import { Observable, of } from 'rxjs';

@Get()
findAll(): Observable<any> {
  return of({ message: 'Success' });
}

状态码 #

@HttpCode装饰器 #

typescript
import { Controller, Post, Get, HttpCode, HttpStatus } from '@nestjs/common';

@Controller('users')
export class UsersController {
  @Post()
  @HttpCode(HttpStatus.CREATED)  // 201
  create() {
    return 'User created';
  }

  @Get()
  @HttpCode(HttpStatus.OK)  // 200
  findAll() {
    return 'All users';
  }

  @Delete(':id')
  @HttpCode(HttpStatus.NO_CONTENT)  // 204
  remove() {
    return;
  }
}

常用HTTP状态码 #

状态码 枚举值 说明
200 HttpStatus.OK 成功
201 HttpStatus.CREATED 创建成功
204 HttpStatus.NO_CONTENT 无内容
400 HttpStatus.BAD_REQUEST 错误请求
401 HttpStatus.UNAUTHORIZED 未授权
403 HttpStatus.FORBIDDEN 禁止访问
404 HttpStatus.NOT_FOUND 未找到
500 HttpStatus.INTERNAL_SERVER_ERROR 服务器错误

响应头 #

@Header装饰器 #

typescript
import { Controller, Get, Header } from '@nestjs/common';

@Controller('users')
export class UsersController {
  @Get()
  @Header('Cache-Control', 'none')
  @Header('X-Custom-Header', 'value')
  findAll() {
    return 'All users';
  }
}

Express响应对象 #

使用@Res() #

typescript
import { Controller, Get, Res } from '@nestjs/common';
import { Response } from 'express';

@Controller('users')
export class UsersController {
  @Get()
  findAll(@Res() response: Response) {
    response.status(200).json({
      message: 'Success',
      data: [],
    });
  }
}

流式响应 #

typescript
import { Readable } from 'stream';

@Get('stream')
stream(@Res() response: Response) {
  const stream = new Readable({
    read() {},
  });

  stream.push('Hello ');
  stream.push('World!');
  stream.push(null);

  response.setHeader('Content-Type', 'text/plain');
  stream.pipe(response);
}

Server-Sent Events #

typescript
import { MessageEvent } from '@nestjs/common';

@Get('sse')
sse(): Observable<MessageEvent> {
  return interval(1000).pipe(
    map(() => ({
      data: { time: new Date().toISOString() },
    })),
  );
}

文件响应 #

文件下载 #

typescript
import { Controller, Get, StreamableFile } from '@nestjs/common';
import { createReadStream } from 'fs';
import { join } from 'path';

@Controller('download')
export class DownloadController {
  @Get()
  getFile(): StreamableFile {
    const file = createReadStream(join(process.cwd(), 'package.json'));
    return new StreamableFile(file);
  }

  @Get('custom')
  getCustomFile(@Res() response: Response): StreamableFile {
    const file = createReadStream(join(process.cwd(), 'package.json'));
    response.setHeader('Content-Type', 'application/json');
    response.setHeader('Content-Disposition', 'attachment; filename="package.json"');
    return new StreamableFile(file);
  }
}

图片响应 #

typescript
@Get('image')
getImage(@Res() response: Response) {
  const file = createReadStream(join(process.cwd(), 'assets/logo.png'));
  response.setHeader('Content-Type', 'image/png');
  file.pipe(response);
}

重定向 #

静态重定向 #

typescript
import { Controller, Get, Redirect } from '@nestjs/common';

@Controller()
export class AppController {
  @Get('docs')
  @Redirect('https://docs.nestjs.com', 302)
  getDocs() {}
}

动态重定向 #

typescript
@Get('redirect')
@Redirect()
redirectTo(@Query('url') url: string) {
  return {
    url: url || 'https://nestjs.com',
    statusCode: 302,
  };
}

响应格式化 #

统一响应格式 #

typescript
export class ResponseDto<T> {
  code: number;
  message: string;
  data: T;
  timestamp: string;

  constructor(data: T, message = 'Success', code = 200) {
    this.code = code;
    this.message = message;
    this.data = data;
    this.timestamp = new Date().toISOString();
  }
}

@Get()
findAll(): ResponseDto<User[]> {
  const users = this.usersService.findAll();
  return new ResponseDto(users);
}

使用拦截器格式化 #

typescript
import {
  Injectable,
  NestInterceptor,
  ExecutionContext,
  CallHandler,
} from '@nestjs/common';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

export interface Response<T> {
  code: number;
  message: string;
  data: T;
  timestamp: string;
}

@Injectable()
export class TransformInterceptor<T>
  implements NestInterceptor<T, Response<T>>
{
  intercept(
    context: ExecutionContext,
    next: CallHandler,
  ): Observable<Response<T>> {
    return next.handle().pipe(
      map(data => ({
        code: 200,
        message: 'Success',
        data,
        timestamp: new Date().toISOString(),
      })),
    );
  }
}

全局应用:

typescript
app.useGlobalInterceptors(new TransformInterceptor());

分页响应 #

typescript
export class PaginatedDto<T> {
  data: T[];
  total: number;
  page: number;
  limit: number;
  totalPages: number;
}

@Get()
async findAll(
  @Query('page') page: number = 1,
  @Query('limit') limit: number = 10,
): Promise<PaginatedDto<User>> {
  const [data, total] = await this.usersService.findAndCount(page, limit);
  return {
    data,
    total,
    page,
    limit,
    totalPages: Math.ceil(total / limit),
  };
}

响应缓存 #

使用@CacheKey #

typescript
import { Controller, Get, CacheKey, CacheTTL } from '@nestjs/common';
import { CacheInterceptor } from '@nestjs/cache-manager';

@Controller('users')
@UseInterceptors(CacheInterceptor)
export class UsersController {
  @Get()
  @CacheKey('users_all')
  @CacheTTL(60)
  findAll() {
    return this.usersService.findAll();
  }
}

配置缓存模块 #

typescript
import { CacheModule, Module } from '@nestjs/common';

@Module({
  imports: [
    CacheModule.register({
      ttl: 60,
      max: 100,
    }),
  ],
})
export class AppModule {}

CORS配置 #

typescript
async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  
  app.enableCors({
    origin: ['https://example.com'],
    methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
    credentials: true,
  });
  
  await app.listen(3000);
}

响应压缩 #

typescript
import compression from 'compression';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.use(compression());
  await app.listen(3000);
}

总结 #

本章学习了NestJS响应处理:

  • 标准响应模式
  • HTTP状态码设置
  • 响应头设置
  • 文件下载和流式响应
  • 重定向
  • 响应格式化
  • 响应缓存

接下来,让我们学习 异常处理

最后更新:2026-03-28