NodeJS全栈开发面试题讲解——P2Express / Nest 后端开发
✅ 2.1 Express 的中间件机制?如何组织一个 RESTful API 项目?
面试官好,我来讲讲 Express 的中间件机制,它是 Express 架构的核心,也是组织 RESTful 项目的基础。
🧩 什么是中间件?
中间件(Middleware)就是一类函数,它们可以对 req
和 res
进行加工、拦截、判断,决定是否将请求传递给下一个处理函数。
✨ 形式:
function (req, res, next) { ... }
-
req
:请求对象; -
res
:响应对象; -
next()
:调用下一个中间件。
🧱 中间件执行顺序是按注册顺序的:
app.use(logger);
app.use(auth);
app.get('/user', controller);
📦 常见中间件分类:
类型 | 示例 |
---|---|
应用级 | app.use() 全局中间件 |
路由级 | router.use() 、局部中间件 |
错误处理中间件 | 4 个参数 (err, req, res, next) |
内置中间件 | express.json() 、static() |
第三方中间件 | cors 、body-parser 、morgan |
📐 如何组织一个 RESTful 项目?
文件结构推荐:
src/
├── routes/
│ └── user.js
├── controllers/
│ └── userController.js
├── middlewares/
│ └── auth.js
├── services/
│ └── userService.js
├── utils/
├── app.js
核心思想:路由-控制器-服务分离,中间件集中注册。
// routes/user.js
const express = require('express');
const router = express.Router();
const userController = require('../controllers/userController');
const auth = require('../middlewares/auth');router.get('/profile', auth, userController.getProfile);
module.exports = router;
✅ 2.2 如何处理接口异常?如何做统一异常拦截?
在 Express 和 NestJS 中,我分别有两种做法来实现“统一异常处理”,这对于生产级项目来说是必不可少的。
✅ Express:统一异常处理
Express 中通过定义 错误处理中间件 来统一拦截异常。
// app.js
app.use((err, req, res, next) => {console.error(err.stack);res.status(500).json({ code: 500, message: 'Internal Server Error' });
});
在路由/服务中使用 next(err)
触发:
try {throw new Error('DB Error');
} catch (err) {next(err);
}
✅ NestJS:内置异常过滤器机制
NestJS 提供 @Catch()
装饰器,可以创建自定义异常过滤器。
// common/filters/http-exception.filter.ts
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {catch(exception: HttpException, host: ArgumentsHost) {const ctx = host.switchToHttp();const res = ctx.getResponse<Response>();const status = exception.getStatus();res.status(status).json({statusCode: status,message: exception.message,timestamp: new Date().toISOString(),});}
}
注册方式:
// main.ts
app.useGlobalFilters(new HttpExceptionFilter());
✅ 2.3 JWT 鉴权的完整流程?Token 存储在哪里最安全?
我来详细说明一个完整的 JWT 登录鉴权流程,以及 token 应该如何存储最安全。
🔐 JWT 基本结构:
JWT 分为三段:
Header.Payload.Signature
-
Header:加密算法
-
Payload:用户数据(如 userId, role)
-
Signature:签名,防篡改
✅ JWT 鉴权流程:
-
用户登录时提交用户名 + 密码;
-
服务端验证后,使用
jsonwebtoken
生成 Token:
const token = jwt.sign({ userId: 123 }, secret, { expiresIn: '1h' });
-
客户端收到后,将 Token 储存并在后续请求中带上:
Authorization: Bearer <token>
-
服务端中间件负责解析、验证 Token 并附加用户信息:
const decoded = jwt.verify(token, secret);
req.user = decoded;
✅ Token 存储方案对比:
存储位置 | 安全性 | 建议使用场景 |
---|---|---|
LocalStorage | 易被 XSS 获取 | 适合开发调试、测试环境 |
Cookie(HttpOnly) | 安全、防 XSS | ✅ 最安全,推荐生产环境 |
SessionStorage | 随刷新丢失 | 不适合长期登录会话 |
✅ 2.4 如何实现接口的权限控制?支持不同角色访问不同资源?
我习惯使用“路由权限 + 用户角色”的结合方式来实现精细化权限控制。
🎯 实现思路:
-
登录时,在 JWT 中记录用户的
role
或permissions
; -
使用中间件或守卫(Guard)读取用户角色,匹配当前路由所需权限;
-
不满足则返回 403 Forbidden。
✅ Express 示例:
function roleGuard(roles) {return (req, res, next) => {const userRole = req.user.role;if (roles.includes(userRole)) next();else res.status(403).json({ message: 'Forbidden' });};
}router.get('/admin', auth, roleGuard(['admin']), adminController.doSomething);
✅ NestJS 示例(守卫 + 装饰器):
// roles.decorator.ts
export const Roles = (...roles: string[]) => SetMetadata('roles', roles);// roles.guard.ts
@Injectable()
export class RolesGuard implements CanActivate {canActivate(context: ExecutionContext): boolean {const roles = this.reflector.get<string[]>('roles', context.getHandler());const user = context.switchToHttp().getRequest().user;return roles.includes(user.role);}
}
使用:
@UseGuards(RolesGuard)
@Roles('admin')
@Get('/admin')
getAdminData() { ... }
✅ 2.5 如何在 NestJS 中使用装饰器、模块、依赖注入机制?
NestJS 的核心就是基于模块化的架构、装饰器驱动和依赖注入。我详细说明下。
✅ 模块(Module)
每个模块(@Module
)组织了 controller、service、provider 的集合。
@Module({controllers: [UserController],providers: [UserService],exports: [UserService]
})
export class UserModule {}
✅ 控制器(Controller)
控制请求和响应,对应 RESTful 接口。
@Controller('user')
export class UserController {constructor(private readonly userService: UserService) {}@Get()findAll() {return this.userService.findAll();}
}
✅ 服务(Service)+ 依赖注入(DI)
@Injectable()
export class UserService {findAll() { return [{ name: 'Tom' }]; }
}
Service 是业务逻辑层,通过构造函数注入。
// Controller 中自动注入
constructor(private readonly userService: UserService) {}
✅ 自定义装饰器(Decorator)
用于封装通用逻辑,如读取 token 中用户 ID。
export const CurrentUser = createParamDecorator((data, ctx: ExecutionContext) => {const request = ctx.switchToHttp().getRequest();return request.user;},
);
使用:
@Get('/profile')
getProfile(@CurrentUser() user) {return user;
}
✅ 总结对照表:
问题 | 技术点 |
---|---|
2.1 | Express 中间件机制、项目结构设计 |
2.2 | 错误处理中间件 vs Nest 异常过滤器 |
2.3 | JWT 鉴权流程、Token 安全存储 |
2.4 | RBAC 角色权限控制实现方式 |
2.5 | Nest 模块系统、依赖注入、装饰器应用 |