在JavaScript生态中,使用Node.js结合Express等框架开发RESTful API是非常常见的场景,遵循统一的最佳实践能够让接口更易用、更易维护,也能降低后续迭代的成本。

路由设计规范
RESTful API的核心是通过HTTP方法和资源路径来明确接口的作用,路由设计需要符合行业通用规范,避免自定义的非标准路径。
- 资源路径使用名词复数形式,比如获取用户列表使用
/users,而不是/getUserList - HTTP方法对应操作类型:GET用于查询,POST用于新增,PUT用于全量更新,PATCH用于部分更新,DELETE用于删除
- 路径参数用于标识具体资源,比如获取单个用户使用
/users/:id,查询参数用于过滤、分页等条件,比如/users?page=1&limit=10
以下是符合规范的路由定义示例:
const express = require('express');
const router = express.Router();
// 获取用户列表
router.get('/users', (req, res) => {
// 处理查询逻辑
});
// 获取单个用户
router.get('/users/:id', (req, res) => {
const { id } = req.params;
// 根据id查询用户逻辑
});
// 新增用户
router.post('/users', (req, res) => {
// 处理新增用户逻辑
});
// 更新用户
router.put('/users/:id', (req, res) => {
const { id } = req.params;
// 处理全量更新逻辑
});
// 删除用户
router.delete('/users/:id', (req, res) => {
const { id } = req.params;
// 处理删除逻辑
});
module.exports = router;
统一响应格式
所有接口的响应格式保持一致,能够让前端调用时处理逻辑更统一,减少额外的适配成本。
建议的响应格式包含三个核心字段:
- code:业务状态码,和HTTP状态码区分开,用于标识具体的业务结果,比如200表示成功,1001表示参数错误
- message:响应描述信息,成功时返回操作成功的提示,失败时返回具体的错误原因
- data:响应数据,成功时返回对应的业务数据,失败时可以为null
以下是统一响应格式的封装示例:
// 响应工具函数
const responseUtil = {
success: (res, data = null, message = '操作成功') => {
res.json({
code: 200,
message,
data
});
},
error: (res, code = 500, message = '操作失败', data = null) => {
res.json({
code,
message,
data
});
}
};
module.exports = responseUtil;
在路由中使用该工具函数的示例:
const express = require('express');
const responseUtil = require('./responseUtil');
const router = express.Router();
router.get('/users', (req, res) => {
try {
// 模拟查询到的用户数据
const userList = [
{ id: 1, name: '张三', age: 20 },
{ id: 2, name: '李四', age: 22 }
];
responseUtil.success(res, userList);
} catch (err) {
responseUtil.error(res, 500, '查询用户列表失败');
}
});
module.exports = router;
参数校验处理
所有传入的参数都需要进行校验,避免无效参数或者恶意参数进入业务逻辑,减少运行时错误和安全风险。
可以使用joi或者express-validator等库进行参数校验,以下是使用express-validator的示例:
const { body, validationResult } = require('express-validator');
const userValidator = [
body('name').notEmpty().withMessage('用户名不能为空').isString().withMessage('用户名必须是字符串'),
body('age').isInt({ min: 1, max: 120 }).withMessage('年龄必须是1到120之间的整数')
];
router.post('/users', userValidator, (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
// 返回参数校验错误
return responseUtil.error(res, 1001, errors.array()[0].msg);
}
// 参数校验通过,处理新增逻辑
const { name, age } = req.body;
// 模拟新增用户
const newUser = { id: Date.now(), name, age };
responseUtil.success(res, newUser, '新增用户成功');
});
错误处理最佳实践
统一的错误处理能够避免错误信息泄露,也能让错误响应格式和正常响应保持一致。
首先需要定义自定义错误类,区分业务错误和系统错误:
class AppError extends Error {
constructor(code, message) {
super(message);
this.code = code;
this.name = 'AppError';
}
}
module.exports = AppError;
然后在Express中注册全局错误处理中间件:
const express = require('express');
const AppError = require('./AppError');
const responseUtil = require('./responseUtil');
const app = express();
app.use(express.json());
// 业务代码中抛出错误示例
router.get('/users/:id', (req, res, next) => {
const { id } = req.params;
// 模拟用户不存在的场景
if (id === '999') {
return next(new AppError(1002, '用户不存在'));
}
// 模拟查询到用户
const user = { id: 1, name: '张三', age: 20 };
responseUtil.success(res, user);
});
// 全局错误处理中间件,放在所有路由之后
app.use((err, req, res, next) => {
if (err instanceof AppError) {
// 业务错误,返回对应的业务状态码和错误信息
responseUtil.error(res, err.code, err.message);
} else {
// 系统错误,返回通用的服务器错误提示,避免泄露敏感信息
console.error(err); // 系统错误记录日志
responseUtil.error(res, 500, '服务器内部错误');
}
});
安全防护实践
RESTful API需要考虑常见的安全风险,以下是几个核心的安全防护点:
- 使用
helmet中间件设置安全的HTTP头,防范常见的Web安全攻击 - 对用户输入的内容进行转义,避免XSS攻击,尤其是返回给前端的内容如果包含用户输入,需要做好转义处理
- 对敏感接口添加身份验证和权限校验,比如使用JWT令牌验证用户身份,只有合法用户才能访问对应接口
- 限制接口的请求频率,避免接口被恶意刷取,可以使用
express-rate-limit中间件实现
以下是添加基础安全防护的示例:
const helmet = require('helmet');
const rateLimit = require('express-rate-limit');
const app = express();
// 设置安全HTTP头
app.use(helmet());
// 限制请求频率,每个IP每15分钟最多请求100次
const limiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 100,
message: '请求过于频繁,请稍后再试'
});
app.use(limiter);
// JWT验证中间件示例
const verifyToken = (req, res, next) => {
const token = req.headers['authorization'];
if (!token) {
return responseUtil.error(res, 401, '未登录,请先登录');
}
// 验证token的逻辑,这里省略具体实现
try {
// const decoded = jwt.verify(token, 'secretKey');
// req.user = decoded;
next();
} catch (err) {
return responseUtil.error(res, 401, '登录已过期,请重新登录');
}
};
// 需要登录的接口添加验证中间件
router.get('/users/profile', verifyToken, (req, res) => {
// 返回当前登录用户的信息
responseUtil.success(res, { id: 1, name: '张三' });
});
性能优化建议
提升RESTful API的性能可以从以下几个方面入手:
- 对频繁查询的接口添加缓存,比如使用Redis缓存热点数据,减少数据库查询次数
- 对于返回大量数据的接口,支持分页查询,避免一次性返回过多数据导致响应缓慢
- 压缩响应数据,使用
compression中间件开启Gzip压缩,减少传输数据量 - 避免在接口中执行耗时的同步操作,尽量使用异步处理,耗时任务可以放到消息队列中处理
以下是开启Gzip压缩和分页查询的示例:
const compression = require('compression');
const app = express();
// 开启Gzip压缩
app.use(compression());
// 分页查询示例
router.get('/users', (req, res) => {
const { page = 1, limit = 10 } = req.query;
const pageNum = parseInt(page);
const limitNum = parseInt(limit);
// 模拟分页查询逻辑
const allUsers = []; // 假设这里是所有用户数据
const startIndex = (pageNum - 1) * limitNum;
const endIndex = startIndex + limitNum;
const pageData = allUsers.slice(startIndex, endIndex);
responseUtil.success(res, {
list: pageData,
total: allUsers.length,
page: pageNum,
limit: limitNum
});
});
JavaScriptRESTful_APINode.jsExpress修改时间:2026-07-09 02:54:37