Serialization 控制对象如何转换成响应中发送的 JSON — 至关重要的是,排除敏感字段(如密码)并塑造输出。NestJS 通过 ClassSerializerInterceptor 和 class-transformer 装饰器来处理这个问题。
为什么这很重要:数据泄漏的问题
()
() {
..(id);
}
直接返回数据库实体会暴露不应该到达客户端的字段(密码哈希、内部标志、令牌)— 这是一个严重的安全/隐私问题。
import { Exclude } from "class-transformer";
export class User {
id: number;
name: string;
email: string;
@Exclude() // this field is REMOVED from responses
password: string;
}
// enable the serializer interceptor (globally or per-controller)
@UseInterceptors(ClassSerializerInterceptor)
@Controller("users")
export class UsersController {
@Get(":id")
findOne(@Param("id") id): User {
return this.usersService.findOne(id); // password is automatically stripped
}
}
// or globally: app.useGlobalInterceptors(new ClassSerializerInterceptor(app.get(Reflector)))
ClassSerializerInterceptor 在序列化响应时应用 class-transformer 装饰器,所以 @Exclude() 字段会自动被移除 — 但只有在你返回类实例时(不是普通对象)。
export class User {
@Expose() id: number; // explicitly include (with excludeAll strategy)
@Exclude() password: string; // remove from output
@Expose({ name: "full_name" }) // rename in the output
name: string;
@Transform(({ value }) => value.toUpperCase()) // transform the value
code: string;
@Exclude({ toPlainOnly: true }) // exclude only when serializing OUT (not on input)
internalField: string;
}
// ⚠️ the interceptor only transforms CLASS INSTANCES — plain objects pass through unchanged
return new User(data); // ✅ decorators apply
return plainToInstance(User, data); // ✅ convert a plain object to an instance
return { ...data }; // ❌ plain object — @Exclude is IGNORED!
一个常见的陷阱:序列化装饰器只对实际的类实例有效,所以你必须返回一个实例(ORM 实体通常是实例;手动构建的普通对象需要转换)。
Instead of decorating entities, map to a separate Response DTO containing only the
fields meant for the client — explicit, decoupled from the DB model, and very safe.
控制响应序列化对于安全性和清晰的 API 设计都很重要。
最关键的原因是防止敏感数据泄漏 — 直接返回数据库实体可能会暴露密码哈希、内部字段、令牌或其他绝不应该到达客户端的数据,这是一个常见且严重的漏洞。
NestJS 的 ClassSerializerInterceptor 与 class-transformer 装饰器(@Exclude、@Expose、@Transform)提供了一种清晰、声明式的方式来塑造响应 — 自动去除被排除的字段、重命名和转换值。
理解这一点是任何返回用户或域数据的 API 每天都必需的知识,而了解关键陷阱 — 序列化只对类实例有效,不对普通对象有效(这是"为什么密码仍然显示?"bug 的常见来源)— 在实践中非常重要。
同样有价值的是认识专用响应 DTO 的替代模式(将实体映射到仅包含客户端安全字段的显式输出类),这将 API 合同与数据库模型解耦,是处理敏感数据的最安全方法。
正确控制序列化是安全、设计良好的 NestJS API 的标志,也是处理任何非公开数据的真实应用中经常相关的问题。