Node.js 和 Express 面试问题总结
文章目录
- Node.js 和 Express 面试问题总结
- 核心 Node.js 概念
- 1. 什么是 Node.js?它的主要特点是什么?
- 2. 解释 Node.js 的事件循环机制
- 3. 什么是回调地狱?如何避免?
- 4. Node.js 如何处理错误?
- Express 框架相关问题
- 5. 什么是 Express.js?它的核心特性是什么?
- 6. 解释 Express 中的中间件概念
- 7. 如何在 Express 中处理路由?
- 8. 如何保护 Express 应用的安全?
- 高级问题
- 9. 解释 Node.js 中的 cluster 模块
- 10. 如何优化 Express 应用的性能?
- 11. 解释 RESTful API 设计原则
- 12. 如何处理 Express 中的文件上传?
- 13. 什么是 JWT?如何在 Express 中实现 JWT 认证?
- 14. 如何调试 Node.js 应用?
- 15. 解释 Node.js 中的流 (Streams) 及其类型
- 16. 如何实现 Express 应用的单元测试?
- 17. 解释 Node.js 中的 process 对象
- 18. 什么是 CORS?如何在 Express 中启用它?
- 19. 解释 Node.js 中的 Buffer 类
- 20. 如何实现 Express 应用的用户认证?

Node.js 和 Express 面试问题总结
核心 Node.js 概念
1. 什么是 Node.js?它的主要特点是什么?
答案:Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行时环境,用于构建高性能、可扩展的网络应用程序。主要特点包括:
- 非阻塞 I/O 和事件驱动架构
- 单线程但支持高并发
- 跨平台
- 丰富的包生态系统 (npm)
- 适合 I/O 密集型应用
2. 解释 Node.js 的事件循环机制
答案:事件循环是 Node.js 实现非阻塞 I/O 的核心机制,它允许 Node.js 在不使用多线程的情况下处理大量并发操作。事件循环包括以下阶段:
- 定时器阶段(执行 setTimeout 和 setInterval 回调)
- 待定回调阶段(执行系统操作回调如 TCP 错误)
- 闲置/准备阶段(内部使用)
- 轮询阶段(检索新的 I/O 事件)
- 检查阶段(执行 setImmediate 回调)
- 关闭回调阶段(如 socket.on(‘close’))
3. 什么是回调地狱?如何避免?
答案:回调地狱是指多层嵌套回调函数导致的代码难以阅读和维护的情况。避免方法:
- 使用 Promise 和 async/await
- 模块化代码,拆分回调函数
- 使用流程控制库如 async.js
- 遵循错误优先回调模式
4. Node.js 如何处理错误?
答案:Node.js 中错误处理的主要方式:
- 回调函数中的错误优先模式
- try/catch 处理同步代码错误
- Promise 的 .catch() 方法
- process.on(‘uncaughtException’) 全局捕获
- domain 模块(已弃用)
- 对于异步代码,最好使用 async/await 结合 try/catch
Express 框架相关问题
5. 什么是 Express.js?它的核心特性是什么?
答案:Express 是 Node.js 的一个快速、极简的 web 应用框架。核心特性包括:
- 路由系统
- 中间件支持
- 模板引擎集成
- 错误处理机制
- 简化 HTTP 请求和响应处理
6. 解释 Express 中的中间件概念
答案:中间件是在请求和响应周期中访问请求对象 (req)、响应对象 (res) 和 next 函数的函数。它可以:
- 执行任何代码
- 修改请求和响应对象
- 结束请求-响应周期
- 调用堆栈中的下一个中间件
中间件分为:
- 应用级中间件 (app.use)
- 路由级中间件 (router.use)
- 错误处理中间件
- 内置中间件 (express.static)
- 第三方中间件 (body-parser)
7. 如何在 Express 中处理路由?
答案:Express 提供了简洁的路由定义方式:
// 基本路由
app.METHOD(PATH, HANDLER)// 示例
app.get('/users', (req, res) => {res.send('Get all users');
});// 路由参数
app.get('/users/:id', (req, res) => {res.send(`Get user with ID ${req.params.id}`);
});// 路由模块化
const router = express.Router();
router.get('/', (req, res) => {...});
app.use('/users', router);
8. 如何保护 Express 应用的安全?
答案:保护 Express 应用的安全措施包括:
- 使用 helmet 中间件设置安全 HTTP 头
- 防止跨站脚本攻击 (XSS)
- 防止 SQL 注入攻击
- 使用 csurf 中间件防止 CSRF 攻击
- 限制请求体大小 (express.json({ limit: ‘10kb’ }))
- 使用 rate-limiting 防止暴力攻击
- 正确处理用户输入和输出
- 使用 HTTPS
- 保持依赖项更新
高级问题
9. 解释 Node.js 中的 cluster 模块
答案:cluster 模块允许创建共享同一服务器端口的子进程,利用多核 CPU。主进程管理工作进程,工作进程处理请求。当工作进程崩溃时,主进程可以重启它,提高应用的可靠性。
10. 如何优化 Express 应用的性能?
答案:Express 性能优化方法:
- 使用 gzip 压缩
- 避免同步代码
- 正确使用中间件(按需加载)
- 实现缓存(Redis)
- 使用反向代理(Nginx)
- 负载均衡
- 数据库查询优化
- 使用 PM2 等进程管理器
- 压缩静态资源
- 使用 CDN
11. 解释 RESTful API 设计原则
答案:RESTful API 设计原则包括:
- 客户端-服务器分离
- 无状态(每个请求包含所有必要信息)
- 可缓存
- 统一接口
- 分层系统
- 按需代码(可选)
- 资源标识(URI)
- 通过表示操作资源
- 自描述消息
- 超媒体作为应用状态引擎 (HATEOAS)
12. 如何处理 Express 中的文件上传?
答案:使用 multer 中间件处理文件上传:
const multer = require('multer');
const upload = multer({ dest: 'uploads/' });app.post('/upload', upload.single('file'), (req, res) => {// req.file 是上传的文件信息res.send('File uploaded successfully');
});
13. 什么是 JWT?如何在 Express 中实现 JWT 认证?
答案:JWT (JSON Web Token) 是一种开放标准,用于安全地在各方之间传输信息作为 JSON 对象。Express 中实现:
- 安装 jsonwebtoken 和 express-jwt
- 用户登录时生成 token
- 客户端存储 token 并在请求头中发送
- 服务器验证 token
示例:
const jwt = require('jsonwebtoken');
const expressJwt = require('express-jwt');// 生成 token
const token = jwt.sign({ userId: user.id }, 'secret', { expiresIn: '1h' });// 验证中间件
app.use(expressJwt({ secret: 'secret', algorithms: ['HS256'] }));// 受保护路由
app.get('/protected', (req, res) => {res.send(`Hello ${req.user.userId}`);
});
14. 如何调试 Node.js 应用?
答案:Node.js 调试方法:
- 使用 console.log (最简单但不够强大)
- Node.js 内置调试器 (node inspect)
- Chrome DevTools (–inspect 标志)
- VS Code 调试工具
- 第三方调试工具如 ndb
- 使用 debug 模块
- 日志记录 (winston, morgan)
- 性能分析 (–prof 标志)
15. 解释 Node.js 中的流 (Streams) 及其类型
答案:流是处理读写文件、网络通信等操作的抽象接口,可以高效处理大量数据。流类型包括:
- Readable (可读流 - fs.createReadStream)
- Writable (可写流 - fs.createWriteStream)
- Duplex (双工流 - net.Socket)
- Transform (转换流 - zlib.createGzip)
流的工作模式:
- 流动模式 (flowing) - 数据自动读取
- 暂停模式 (paused) - 必须显式调用 read()
16. 如何实现 Express 应用的单元测试?
答案:Express 应用测试方法:
- 使用测试框架 (Jest, Mocha)
- 使用断言库 (Chai)
- 使用 supertest 测试 HTTP 请求
- 模拟数据库和其他依赖
- 测试路由、中间件和业务逻辑
示例:
const request = require('supertest');
const app = require('../app');describe('GET /users', () => {it('responds with JSON', async () => {const response = await request(app).get('/users').expect('Content-Type', /json/).expect(200);expect(response.body).toBeInstanceOf(Array);});
});
17. 解释 Node.js 中的 process 对象
答案:process 是全局对象,提供当前 Node.js 进程的信息和控制。常用属性和方法:
- process.env - 环境变量
- process.argv - 命令行参数
- process.cwd() - 当前工作目录
- process.exit() - 退出进程
- process.memoryUsage() - 内存使用情况
- process.pid - 进程 ID
- process.on() - 监听进程事件 (如 ‘exit’, ‘uncaughtException’)
18. 什么是 CORS?如何在 Express 中启用它?
答案:CORS (跨源资源共享) 是一种机制,允许网页从不同域的服务器请求资源。在 Express 中启用:
// 使用 cors 中间件
const cors = require('cors');// 全部路由启用
app.use(cors());// 或配置特定选项
app.use(cors({origin: 'https://example.com',methods: ['GET', 'POST'],allowedHeaders: ['Content-Type']
}));// 或单个路由启用
app.get('/products', cors(), (req, res) => {res.json({msg: 'This is CORS-enabled for a Single Route'});
});
19. 解释 Node.js 中的 Buffer 类
答案:Buffer 类用于处理二进制数据,是全局可用的。在 Node.js 中,当需要处理 TCP 流、文件系统操作或其他需要处理原始二进制数据的场景时使用 Buffer。主要方法:
- Buffer.alloc(size) - 创建指定大小的 buffer
- Buffer.from(array/string) - 从数组或字符串创建 buffer
- buf.toString() - 将 buffer 转为字符串
- buf.write() - 向 buffer 写入数据
- Buffer.concat() - 连接多个 buffer
20. 如何实现 Express 应用的用户认证?
答案:Express 用户认证实现方式:
-
基于会话的认证:
- 使用 express-session
- 存储会话数据 (内存或 Redis)
- 使用 passport.js 简化流程
-
基于令牌的认证:
- JWT (JSON Web Tokens)
- OAuth (使用 passport-oauth)
-
第三方认证:
- Google/Facebook/Twitter 登录 (使用 passport 策略)
示例 (Passport 本地策略):
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;passport.use(new LocalStrategy((username, password, done) => {User.findOne({ username }, (err, user) => {if (err) return done(err);if (!user) return done(null, false);if (!user.verifyPassword(password)) return done(null, false);return done(null, user);});}
));app.post('/login', passport.authenticate('local', { successRedirect: '/',failureRedirect: '/login'})
);