面试题答案
一键面试1. 类型定义
首先,定义基础的 Request
扩展类型。假设 user
类型和 paymentInfo
类型如下:
// 定义用户类型
type User = {
id: string;
name: string;
// 其他用户相关属性
};
// 定义支付信息类型,其中 userId 与 User 中的 id 匹配
type PaymentInfo = {
userId: string;
amount: number;
// 其他支付相关属性
};
// 定义 Express 请求扩展类型
declare global {
namespace Express {
interface Request {
user?: User;
paymentInfo?: PaymentInfo;
}
}
}
2. 中间件实现
用户认证中间件
import express, { Request, Response, NextFunction } from 'express';
const userAuthMiddleware = (): ((req: Request, res: Response, next: NextFunction) => void) => {
return (req, res, next) => {
// 模拟用户认证逻辑,假设认证成功后获取到用户信息
const user: User = { id: '123', name: 'John Doe' };
req.user = user;
next();
};
};
支付相关中间件
const paymentMiddleware = (): ((req: Request, res: Response, next: NextFunction) => void) => {
return (req, res, next) => {
if (!req.user) {
return res.status(401).send('User not authenticated');
}
// 模拟支付信息获取逻辑,确保 userId 与 user 中的 id 匹配
const paymentInfo: PaymentInfo = { userId: req.user.id, amount: 100 };
req.paymentInfo = paymentInfo;
next();
};
};
3. 应用中间件并确保类型安全和一致性
const app = express();
// 使用用户认证中间件
app.use(userAuthMiddleware());
// 使用支付相关中间件
app.use(paymentMiddleware());
// 处理业务逻辑的路由,确保类型安全
app.get('/payment', (req, res) => {
if (!req.paymentInfo) {
return res.status(500).send('Payment info not available');
}
res.send(`Payment amount: ${req.paymentInfo.amount}`);
});
const port = 3000;
app.listen(port, () => {
console.log(`Server running on port ${port}`);
});
设计架构和关键实现步骤总结
- 类型定义:通过
declare global
扩展Express.Request
接口,定义不同业务逻辑需要的属性类型,并确保属性类型之间的依赖关系。 - 中间件实现:每个中间件负责添加特定的
req
属性,并进行必要的逻辑处理,如用户认证中间件添加user
属性,支付中间件确保user
已认证并添加paymentInfo
属性。 - 应用中间件:在 Express 应用中依次使用中间件,确保每个中间件按顺序执行,并在后续的路由处理中可以安全地使用扩展的
req
属性,从而确保整个业务逻辑中的类型安全和一致性。