Node.js面试题及详细答案120题(81-92) -- 框架与生态篇
《前后端面试题
》专栏集合了前后端各个知识模块的面试题,包括html,javascript,css,vue,react,java,Openlayers,leaflet,cesium,mapboxGL,threejs,nodejs,mangoDB,MySQL,Linux… 。
文章目录
- 一、本文面试题目录
- 81. 常用的Node.js Web框架有哪些?请对比它们的优缺点。
- 82. Express框架的核心特点是什么?如何使用Express创建路由?
- 核心特点:
- 示例:使用Express创建路由
- 83. Express中间件的执行顺序是怎样的?如何自定义Express中间件?
- 执行顺序:
- 自定义中间件示例:
- 84. Koa框架和Express框架有什么区别?Koa的洋葱模型是什么?
- 核心区别:
- 洋葱模型:
- 85. 什么是Next.js?它有哪些核心功能?
- 86. NestJS框架的特点是什么?它适合开发什么类型的应用?
- 核心特点:
- 适用场景:
- 87. Egg.js的约定优于配置(Convention over Configuration)是什么意思?
- 具体体现:
- 88. 如何使用Express实现RESTful API?
- 89. Express中如何处理静态资源?
- 示例:
- 90. Koa中如何使用`async/await`处理异步操作?
- 示例:异步数据库操作
- 91. 什么是MVC架构?在Node.js框架中如何体现?
- Node.js框架中的体现:
- 92. 如何使用JWT(JSON Web Token)在Node.js中实现身份认证?
- 实现步骤(使用`jsonwebtoken`库):
- 二、120道Node.js面试题目录列表
一、本文面试题目录
81. 常用的Node.js Web框架有哪些?请对比它们的优缺点。
Node.js生态中有多个主流Web框架,各自适用于不同场景,以下是常见框架的对比:
框架 | 优点 | 缺点 | 适用场景 |
---|---|---|---|
Express | 轻量灵活、生态成熟、学习成本低 | 无内置功能(需依赖中间件)、回调嵌套问题 | 小型API、快速原型开发 |
Koa | 基于async/await、洋葱模型、轻量可扩展 | 生态较Express弱、需自行集成功能 | 中型应用、注重异步流程控制 |
NestJS | 模块化架构、支持TypeScript、适合团队协作 | 学习成本高、配置复杂 | 大型企业级应用、微服务 |
Next.js | 支持SSR/SSG、路由自动配置、性能优化 | 更偏向前端框架、后端功能需额外集成 | 前端渲染为主的Web应用 |
Egg.js | 约定优于配置、内置安全与扩展机制 | 灵活性较低、定制化开发受限 | 中大型团队标准化开发 |
原理说明:
不同框架的设计理念差异较大,例如Express强调“最小化”,通过中间件扩展功能;Koa通过洋葱模型优化异步流程;NestJS则借鉴Angular的模块化思想,适合复杂应用架构。
82. Express框架的核心特点是什么?如何使用Express创建路由?
核心特点:
- 轻量灵活:仅提供核心功能,通过中间件扩展
- 路由系统:简洁的路由定义方式,支持RESTful风格
- 中间件机制:可串联多个中间件处理请求
- 模板引擎支持:兼容多种模板引擎(如EJS、Pug)
- 生态丰富:拥有大量第三方中间件(如
cors
、morgan
)
示例:使用Express创建路由
const express = require('express');
const app = express();// 基础路由
app.get('/', (req, res) => {res.send('首页');
});// 带参数的路由
app.get('/user/:id', (req, res) => {// 获取URL参数const userId = req.params.id;res.send(`用户ID:${userId}`);
});// 路由模块化(推荐)
const userRouter = express.Router();
userRouter.post('/login', (req, res) => {res.send('登录成功');
});
userRouter.get('/profile', (req, res) => {res.send('用户资料');
});
// 挂载路由
app.use('/user', userRouter);app.listen(3000, () => {console.log('服务器运行在3000端口');
});
83. Express中间件的执行顺序是怎样的?如何自定义Express中间件?
执行顺序:
- 中间件按定义顺序依次执行,遵循“先进先出”原则
- 每个中间件需调用
next()
方法才能触发下一个中间件 - 若中间件未调用
next()
且未响应请求,会导致请求挂起
自定义中间件示例:
const express = require('express');
const app = express();// 1. 日志中间件(记录请求信息)
const logger = (req, res, next) => {console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);next(); // 调用next()执行下一个中间件
};// 2. 身份验证中间件
const auth = (req, res, next) => {const token = req.headers.authorization;if (token) {next(); // 验证通过,继续执行} else {res.status(401).send('未授权'); // 验证失败,直接响应}
};// 使用中间件
app.use(logger); // 全局中间件(所有路由生效)
app.use('/admin', auth); // 局部中间件(仅/admin路由生效)app.get('/', (req, res) => {res.send('首页');
});app.get('/admin/dashboard', (req, res) => {res.send('管理员面板');
});app.listen(3000);
84. Koa框架和Express框架有什么区别?Koa的洋葱模型是什么?
核心区别:
对比项 | Express | Koa |
---|---|---|
异步处理 | 回调函数(易嵌套) | async/await(扁平化) |
中间件模型 | 线性执行 | 洋葱模型(支持后置处理) |
内置功能 | 包含路由、静态文件等 | 极简核心(需自行扩展) |
响应处理 | res.send() | ctx.body |
洋葱模型:
Koa的中间件执行流程类似洋葱结构,先从外到内执行请求逻辑,再从内到外执行响应逻辑,支持在中间件中同时处理请求和响应。
示例:
const Koa = require('koa');
const app = new Koa();// 中间件1
app.use(async (ctx, next) => {console.log('中间件1 开始');await next(); // 等待下一个中间件执行完成console.log('中间件1 结束');
});// 中间件2
app.use(async (ctx, next) => {console.log('中间件2 开始');await next();console.log('中间件2 结束');ctx.body = 'Hello Koa';
});app.listen(3000);
// 执行结果:
// 中间件1 开始
// 中间件2 开始
// 中间件2 结束
// 中间件1 结束
85. 什么是Next.js?它有哪些核心功能?
Next.js是基于React的全栈框架,专注于前端渲染优化和开发体验,核心功能包括:
-
渲染方式多样化:
- 服务端渲染(SSR):提升首屏加载速度和SEO
- 静态站点生成(SSG):预渲染页面,适合静态内容
- 增量静态再生(ISR):定期更新静态页面,平衡性能与实时性
-
路由系统:
- 基于文件系统的自动路由(无需手动配置)
- 支持动态路由(如
[id].js
)和嵌套路由
-
性能优化:
- 自动代码分割(按需加载)
- 图像优化(
next/image
组件) - 脚本优化(
next/script
组件)
-
API路由:
可在pages/api
目录下创建后端接口,无需单独部署服务器。
示例:创建API路由(pages/api/hello.js
)
export default function handler(req, res) {res.status(200).json({ message: 'Hello Next.js' });
}
86. NestJS框架的特点是什么?它适合开发什么类型的应用?
核心特点:
- 模块化架构:通过
Module
、Controller
、Service
分层组织代码 - 依赖注入:实现松耦合,便于测试和维护
- TypeScript优先:原生支持TypeScript,增强类型安全
- 跨平台兼容:可开发REST API、GraphQL、微服务等
- 丰富的扩展:内置Swagger文档、身份验证等模块
适用场景:
- 大型企业级应用(复杂业务逻辑、团队协作)
- 微服务架构(支持多种微服务通信方式)
- 需要严格类型检查和代码规范的项目
示例:基础模块结构
// cats.controller.ts
import { Controller, Get } from '@nestjs/common';
import { CatsService } from './cats.service';@Controller('cats')
export class CatsController {constructor(private readonly catsService: CatsService) {}@Get()findAll() {return this.catsService.findAll();}
}// cats.service.ts
import { Injectable } from '@nestjs/common';@Injectable()
export class CatsService {findAll() {return ['cat1', 'cat2'];}
}
87. Egg.js的约定优于配置(Convention over Configuration)是什么意思?
“约定优于配置”是Egg.js的核心设计理念,指通过预设规范减少配置成本,开发者无需手动配置常规项,只需遵循约定即可快速开发。
具体体现:
-
目录结构约定:
app/controller
:存放控制器(处理请求)app/service
:存放服务(业务逻辑)app/middleware
:存放中间件config/
:存放配置文件(默认配置可被覆盖)
-
命名规范:
- 控制器方法自动映射为路由(如
UserController
的index
方法对应/user
) - 配置文件按环境区分(
config.default.js
、config.prod.js
)
- 控制器方法自动映射为路由(如
-
功能默认集成:
- 内置日志、安全策略、错误处理等功能
- 中间件按约定顺序加载
优势:降低团队协作成本,统一代码风格,减少重复配置。
88. 如何使用Express实现RESTful API?
RESTful API通过HTTP方法和URL表示资源操作,以下是Express实现示例:
const express = require('express');
const app = express();
app.use(express.json()); // 解析JSON请求体// 模拟数据库
let books = [{ id: 1, title: 'Node.js入门', author: '张三' },{ id: 2, title: 'Express实战', author: '李四' }
];// 1. 获取所有资源(GET)
app.get('/api/books', (req, res) => {res.json(books);
});// 2. 获取单个资源(GET + ID)
app.get('/api/books/:id', (req, res) => {const book = books.find(b => b.id === parseInt(req.params.id));if (!book) return res.status(404).send('资源不存在');res.json(book);
});// 3. 创建资源(POST)
app.post('/api/books', (req, res) => {const newBook = {id: books.length + 1,title: req.body.title,author: req.body.author};books.push(newBook);res.status(201).json(newBook); // 201表示创建成功
});// 4. 更新资源(PUT)
app.put('/api/books/:id', (req, res) => {const book = books.find(b => b.id === parseInt(req.params.id));if (!book) return res.status(404).send('资源不存在');book.title = req.body.title;book.author = req.body.author;res.json(book);
});// 5. 删除资源(DELETE)
app.delete('/api/books/:id', (req, res) => {const index = books.findIndex(b => b.id === parseInt(req.params.id));if (index === -1) return res.status(404).send('资源不存在');books.splice(index, 1);res.status(204).send(); // 204表示无内容
});app.listen(3000);
89. Express中如何处理静态资源?
Express通过内置的express.static
中间件处理静态资源(如图片、CSS、JS文件)。
示例:
const express = require('express');
const app = express();// 1. 基础用法:托管public目录
app.use(express.static('public'));
// 访问:http://localhost:3000/images/logo.png → 对应public/images/logo.png// 2. 自定义虚拟路径
app.use('/static', express.static('public'));
// 访问:http://localhost:3000/static/css/style.css → 对应public/css/style.css// 3. 多个静态目录
app.use(express.static('public'));
app.use(express.static('files')); // 按顺序查找文件app.listen(3000);
原理:express.static
会根据请求路径在指定目录中查找文件,找到则返回文件内容,否则继续执行后续中间件。
90. Koa中如何使用async/await
处理异步操作?
Koa原生支持async/await
,可扁平化异步代码,避免回调嵌套。
示例:异步数据库操作
const Koa = require('koa');
const app = new Koa();
const fs = require('fs/promises'); // 使用Promise版fs模块// 异步中间件
app.use(async (ctx) => {if (ctx.path === '/data') {try {// 读取文件(异步操作)const data = await fs.readFile('data.txt', 'utf8');ctx.body = { content: data };} catch (err) {ctx.status = 500;ctx.body = { error: '读取文件失败' };}}
});app.listen(3000);
说明:
- 在Koa中间件中使用
await
可暂停执行,等待异步操作完成 - 需用
try/catch
捕获异步错误,避免请求异常终止 - 所有中间件都应使用
async
声明,确保洋葱模型正常工作
91. 什么是MVC架构?在Node.js框架中如何体现?
MVC是一种软件架构模式,将应用分为三个部分:
- Model(模型):处理数据和业务逻辑(如数据库操作)
- View(视图):展示数据(如HTML页面、JSON响应)
- Controller(控制器):接收请求,协调Model和View
Node.js框架中的体现:
以Express为例:
// Model(数据模型)
// models/user.js
const User = {findById: async (id) => {// 模拟数据库查询return { id, name: '张三' };}
};// Controller(控制器)
// controllers/userController.js
const UserController = {async getProfile(ctx) {const user = await User.findById(ctx.params.id); // 调用Modelctx.render('profile', { user }); // 渲染View}
};// 路由(连接请求与Controller)
const express = require('express');
const router = express.Router();
router.get('/user/:id', UserController.getProfile);// View(视图,使用EJS模板)
// views/profile.ejs
// <h1><%= user.name %>的资料</h1>
优势:分离关注点,提高代码复用性和可维护性。
92. 如何使用JWT(JSON Web Token)在Node.js中实现身份认证?
JWT是一种无状态身份验证机制,通过加密令牌传递用户信息。
实现步骤(使用jsonwebtoken
库):
-
安装依赖:
npm install jsonwebtoken express
-
示例代码:
const express = require('express'); const jwt = require('jsonwebtoken'); const app = express(); app.use(express.json());// 密钥(生产环境需安全存储) const SECRET = 'your-secret-key';// 1. 登录接口(生成JWT) app.post('/login', (req, res) => {const { username, password } = req.body;// 模拟验证(实际项目需查询数据库)if (username === 'admin' && password === '123') {// 生成令牌(过期时间1小时)const token = jwt.sign({ userId: 1, username: 'admin' }, // payload(不包含敏感信息)SECRET,{ expiresIn: '1h' });res.json({ token });} else {res.status(401).send('用户名或密码错误');} });// 2. 认证中间件(验证JWT) const auth = (req, res, next) => {const token = req.headers.authorization?.split(' ')[1]; // 提取Bearer tokenif (!token) return res.status(401).send('未提供令牌');try {// 验证令牌const decoded = jwt.verify(token, SECRET);req.user = decoded; // 将用户信息存入请求对象next();} catch (err) {res.status(401).send('令牌无效或已过期');} };// 3. 受保护接口 app.get('/profile', auth, (req, res) => {res.json({ user: req.user }); });app.listen(3000);
原理:
- 客户端登录后获取JWT,后续请求在Header中携带令牌
- 服务器验证令牌有效性,无需查询数据库(无状态)
- 适合分布式系统,但令牌无法主动撤销(需结合黑名单机制处理注销)
二、120道Node.js面试题目录列表
文章序号 | Node.js面试题120道 |
---|---|
1 | Node.js面试题及详细答案120道(01-15) |
2 | Node.js面试题及详细答案120道(16-30) |
3 | Node.js面试题及详细答案120道(31-42) |
4 | Node.js面试题及详细答案120道(43-55) |
5 | Node.js面试题及详细答案120道(56-68) |
6 | Node.js面试题及详细答案120道(69-80) |
7 | Node.js面试题及详细答案120道(81-92) |
8 | Node.js面试题及详细答案120道(93-100) |
9 | Node.js面试题及详细答案120道(101-110) |
10 | Node.js面试题及详细答案120道(111-120) |