NestJS响应处理 #
响应处理概述 #
NestJS支持两种响应处理方式:
- 标准模式:返回数据,由框架自动序列化
- 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