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 模块系统、依赖注入、装饰器应用 |
相关文章:
NodeJS全栈开发面试题讲解——P2Express / Nest 后端开发
✅ 2.1 Express 的中间件机制?如何组织一个 RESTful API 项目? 面试官好,我来讲讲 Express 的中间件机制,它是 Express 架构的核心,也是组织 RESTful 项目的基础。 🧩 什么是中间件? 中间件&am…...

从线性代数到线性回归——机器学习视角
真正不懂数学就能理解机器学习其实是个神话。我认为,AI 在商业世界可以不懂数学甚至不懂编程也能应用,但对于技术人员来说,一些基础数学是必须的。本文收集了我认为理解学习本质所必需的数学基础,至少在概念层面要掌握。毕竟&…...

计算机网络相关发展以及常见性能指标
目录 一、因特网概述 1.1 基本概念 1.2 因特网发展的三个阶段 1.3 英特网服务提供者ISP 1.4 英特网的标准化工作 1.5 因特网的组成 1.6 简单总结 二、3种交换方式 2.1 电路交换(Circuit Switching) 2.2 分组交换(Packet Switching&…...

通义灵码:基于MCP的火车票小助手系统全流程设计与技术总结
具体操作步骤请访问:https://blog.csdn.net/ailuloo/article/details/148319336?spm1001.2014.3001.5502 前沿技术应用全景图 一、项目背景与需求分析 目标:基于12306 MCP接口,开发一款解决高峰出行(春运/节假日)痛…...

为什么建立 TCP 连接时,初始序列号不固定?
主要原因有两个方面: 很大程度上避免历史报文被下一个相同四元组的 TCP 连接接收问题(主要方面)防止黑客伪造相同序列号的 TCP 报文被接收 接下来,详细说说第一点 假设每次建立 TCP 连接时,客户端和服务端的初始序列…...

VBA数据库解决方案二十:Select表达式From区域Where条件Order by
《VBA数据库解决方案》教程(版权10090845)是我推出的第二套教程,目前已经是第二版修订了。这套教程定位于中级,是学完字典后的另一个专题讲解。数据库是数据处理的利器,教程中详细介绍了利用ADO连接ACCDB和EXCEL的方法…...

NX753NX756美光科技闪存NX784NX785
技术解读与产品特性 美光科技的NX系列闪存,包括NX753、NX756、NX784、NX785等型号,代表了当前存储技术的前沿水平。这些产品基于先进的NAND闪存技术,采用业界领先的3D TLC NAND技术,实现了高速的数据读写能力。3D TLC NAND技术通…...

使用 pytesseract 构建一个简单 OCR demo
简介 pytesseract 库是 Google Tesseract OCR (光学字符识别)引擎的一个 Python 封装库,使用广泛且功能强大。 构建 使用 pytesseract 构建一个简单 OCR demo。 步骤一:安装必要的库 您需要在您的 Python 环境中安装 pytessera…...
Cesium快速入门到精通系列教程三:添加物体与3D建筑物
Cesium中添加物体与3D建筑物,对于大规模城市模型,推荐使用 3D Tileset;对于简单几何图形,可以使用 Entity API;对于复杂模型,可以使用 GLTF 格式: 一、添加一个点: 在 Cesium 1.93…...

git 如何解决分支合并冲突(VS code可视化解决+gitLab网页解决)
1、定义:两个分支修改了同一文件的同一行代码,无法自动决定如何合并代码,需要人工干预的情况。(假设A提交了文件a,此时B在未拉取代码的情况下,直接提交是会报错的,此时需要拉取之后再提交才会成功ÿ…...

【CF】Day72——Codeforces Round 890 (Div. 2) CDE1 (二分答案 | 交互 + 分治 | ⭐树上背包)
C. To Become Max 题目: 思路: 二分挺好想的,但是check有点不好写 看到最大值,试试二分,如果 x 可以,那么 x - 1 肯定也可以,所以具有单调性,考虑二分 如何check呢?由于…...

单片机寄存器的四种主要类型!
1. 控制寄存器(Control Registers) 专业定义:用于配置硬件行为或触发操作的寄存器。 大白话: 相当于设备的“控制面板”,通过写入特定值来开关功能或调整参数。例如&am…...

智能嗅探AJAX触发:机器学习在动态渲染中的创新应用
一、问题描述:数据加载变“隐形”,采集举步维艰 随着Web技术不断发展,越来越多网站采用了AJAX、动态渲染等技术来加载数据。以今日头条(https://www.toutiao.com)为例,用户打开网页时并不会一次性加载所有…...

【计算机网络】Linux下简单的UDP服务器(超详细)
套接字接口 我们把服务器封装成一个类,当我们定义出一个服务器对象后需要马上初始化服务器,而初始化服务器需要做的第一件事就是创建套接字。 🌎socket函数 这是Linux中创建套接字的系统调用,函数原型如下: int socket(int domain, int typ…...
Java并发编程实战 Day 3:volatile关键字与内存可见性
【Java并发编程实战 Day 3】volatile关键字与内存可见性 开篇 欢迎来到《Java并发编程实战》系列的第3天!本系列旨在带领你从基础到高级逐步掌握Java并发编程的核心概念和最佳实践。 今天我们将重点探讨volatile关键字及其在多线程程序中确保内存可见性的作用。我…...

华为OD机试真题——报文回路(2025A卷:100分)Java/python/JavaScript/C/C++/GO最佳实现
2025 A卷 100分 题型 本专栏内全部题目均提供Java、python、JavaScript、C、C++、GO六种语言的最佳实现方式; 并且每种语言均涵盖详细的问题分析、解题思路、代码实现、代码详解、3个测试用例以及综合分析; 本文收录于专栏:《2025华为OD真题目录+全流程解析+备考攻略+经验分…...
K8s工作流程与YAML实用指南
K8s 工作流程 K8s 采用声明式管理(用户说"要什么",K8s 负责"怎么做")方式,通过 YAML 文件描述期望的状态,K8s控制平面会自动确保实际状态与期望状态一致。 核心工作流程如下: 用户提交…...

功能丰富的PDF处理免费软件推荐
软件介绍 今天给大家介绍一款超棒的PDF工具箱,它处理PDF文档的能力超强,而且是完全免费使用的,没有任何限制。 TinyTools(PC)这款软件,下载完成后即可直接打开使用。在使用过程中,操作完毕后&a…...

Java补充(Java8新特性)(和IO都很重要)
一、Lambda表达式 1.1、为什么使用Lambda表达式 Lambda表达式起步案例 下面源码注释是传统写法,代码是简写表达式写法 import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.function.Consumer;/* * 学什么…...
pycharm debug的时候无法debug到指定的位置就停住不动了
报错大致是这样的,但是直接run没有问题,debug就停住不动了 Traceback (most recent call last): File "/home/mapengsen/.pycharm_helpers/pydev/_pydevd_bundle/pydevd_comm.py", line 467, in start_client s.connect((host, port)) Timeou…...

分布式流处理与消息传递——Kafka ISR(In-Sync Replicas)算法深度解析
Java Kafka ISR(In-Sync Replicas)算法深度解析 一、ISR核心原理 #mermaid-svg-OQtnaUGNQ9PMgbW0 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-OQtnaUGNQ9PMgbW0 .error-icon{fill:#55222…...
极大似然估计例题——正态分布的极大似然估计
设总体 X ∼ N ( μ , σ 2 ) X \sim N(\mu, \sigma^2) X∼N(μ,σ2),其中 μ \mu μ 和 σ 2 \sigma^2 σ2 是未知参数,取样本观测值为 x 1 , x 2 , ⋯ , x n x_1, x_2, \cdots, x_n x1,x2,⋯,xn,求参数 μ \mu μ 和 σ 2 \sigma^2 σ…...
Pull Request Integration 拉取请求集成
今天我想要把我创建的项目,通过修改yaml里面的内容,让我在main分支下的其他分支拉取请求的时候自动化测试拉取的内容,以及将测试结果上传到控制台云端。 首先我通过修改yaml文件里面的内容 name: Build and Teston:push:branches:- mainjobs:…...

OS10.【Linux】yum命令
目录 1.安装软件的几种方法 直接编译源代码,得到可执行程序 使用软件包管理器 2.yum yum list命令 参数解释 yum install命令 yum remove命令 下载链接存放的位置 扩展yum源 实验:安装sl小火车命令 sl命令的选项 方法1:man sl 方法2:读源代码 3.更新yum源 查看…...
头歌数据库课程实验(角色管理)
第1关:创建角色 任务描述 本关任务:创建角色 role1localhost。 相关知识 为了完成本关任务,你需要掌握MySQL的角色管理。 角色信息存放在数据库 mysql 的 user 表中。 user 表中字段: Host:可以登陆数据库的主机地…...
【android bluetooth 协议分析 03】【蓝牙扫描详解 1】【扫描关键函数 btif_dm_search_devices_evt 分析】
1. 背景 本篇我们来对 btif_dm_search_devices_evt 函数进行分析. 这是系统性分析 Bluetooth 协议栈中的设备扫描流程时必须厘清的一环。 1. 为什么要单独分析 btif_dm_search_devices_evt 函数: btif_dm_search_devices_evt 是 BTIF 层中处理设备扫描࿰…...
SpringBoot使用ThreadLocal保存登录用户信息
Java 多线程,系列文章: 《Java多线程》 《Java创建多线程的3种方法:继承Thread类、实现Runnable接口、实现Callable接口》 《Java多线程的同步:synchronized关键字、Lock接口、volatile关键字》 《Java线程池》 《Java线程池实现秒杀功能》 《SpringBoot使用ThreadLocal保存…...

多模态大语言模型arxiv论文略读(102)
Chat2Layout: Interactive 3D Furniture Layout with a Multimodal LLM ➡️ 论文标题:Chat2Layout: Interactive 3D Furniture Layout with a Multimodal LLM ➡️ 论文作者:Can Wang, Hongliang Zhong, Menglei Chai, Mingming He, Dongdong Chen, Ji…...
Ubuntu系统如何部署Crawlab爬虫管理平台(通过docker部署)
Ubuntu系统如何部署Crawlab爬虫管理平台(通过docker部署) 一、安装docker(ubuntu系统版本20.4) 1、更新apt sudo apt-get update2、安装必要的依赖包 sudo apt-get install ca-certificates curl gnupg lsb-release3、添加 Docker 官方 GPG 密钥(清化大学源) # 添加Docke…...
python常用库-pandas、Hugging Face的datasets库(大模型之JSONL(JSON Lines))
文章目录 python常用库pandas、Hugging Face的datasets库(大模型之JSONL(JSON Lines))背景什么是JSONL(JSON Lines)通过pandas读取和保存JSONL文件pandas读取和保存JSONL文件 Hugging Face的datasets库Hugg…...