NodeJS全栈开发面试题讲解——P2Express / Nest 后端开发

2.1 Express 的中间件机制?如何组织一个 RESTful API 项目?

面试官好,我来讲讲 Express 的中间件机制,它是 Express 架构的核心,也是组织 RESTful 项目的基础。

🧩 什么是中间件?

中间件(Middleware)就是一类函数,它们可以对 reqres 进行加工、拦截、判断,决定是否将请求传递给下一个处理函数。

✨ 形式:

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()
第三方中间件 corsbody-parsermorgan

📐 如何组织一个 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 鉴权流程:

  1. 用户登录时提交用户名 + 密码;

  2. 服务端验证后,使用 jsonwebtoken 生成 Token:

const token = jwt.sign({ userId: 123 }, secret, { expiresIn: '1h' });

  1. 客户端收到后,将 Token 储存并在后续请求中带上:

Authorization: Bearer <token>

  1. 服务端中间件负责解析、验证 Token 并附加用户信息:

    const decoded = jwt.verify(token, secret);
    req.user = decoded;


✅ Token 存储方案对比:

存储位置 安全性 建议使用场景
LocalStorage 易被 XSS 获取 适合开发调试、测试环境
Cookie(HttpOnly) 安全、防 XSS ✅ 最安全,推荐生产环境
SessionStorage 随刷新丢失 不适合长期登录会话

2.4 如何实现接口的权限控制?支持不同角色访问不同资源?

我习惯使用"路由权限 + 用户角色"的结合方式来实现精细化权限控制。

🎯 实现思路:

  1. 登录时,在 JWT 中记录用户的 rolepermissions

  2. 使用中间件或守卫(Guard)读取用户角色,匹配当前路由所需权限;

  3. 不满足则返回 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 模块系统、依赖注入、装饰器应用

相关推荐
li35748 小时前
将已有 Vue 项目通过 Electron 打包为桌面客户端的完整步骤
前端·vue.js·electron
Icoolkj8 小时前
VuePress 与 VitePress 深度对比:特性、差异与选型指南
前端·javascript·vue.js
excel8 小时前
CNN 分层详解:卷积、池化到全连接的作用与原理
前端
excel8 小时前
CNN 多层设计详解:从边缘到高级特征的逐层学习
前端
西陵10 小时前
Nx带来极致的前端开发体验——任务编排
前端·javascript·架构
大前端helloworld10 小时前
从初中级如何迈入中高级-其实技术只是“入门卷”
前端·面试
Cosmoshhhyyy10 小时前
Node.js 18+安装及Claude国内镜像使用、idea中claude插件下载指南
node.js
东风西巷11 小时前
Balabolka:免费高效的文字转语音软件
前端·人工智能·学习·语音识别·软件需求
萌萌哒草头将军11 小时前
10个 ES2025 新特性速览!🚀🚀🚀
前端·javascript·vue.js