正在加载文档...
文档内容较大,正在处理中,请稍候
正在加载文档...
文档内容较大,正在处理中,请稍候
本文档详细说明了后端服务中统一响应格式的实现和使用方法,包括响应工具函数、响应格式规范、错误处理等内容。
所有 API 响应都遵循统一的 JSON 格式:
{
"success": true, // 业务成功标识
"code": 200, // HTTP 状态码
"message": "操作成功", // 响应消息
"data": {}, // 响应数据
"timestamp": "2024-12-19T10:30:00.000Z" // 时间戳(ISO 8601)
}响应工具位于 src/utils/response.js:
const { getLogger } = require("../logger");
const logger = getLogger("utils.response");
// 统一响应处理函数
const sendResponse = (req, res, { code, message, data, success }) => {
// ...
};
// 导出方法
module.exports = {
sendResponse,
success,
error,
serverError,
notFound,
unauthorized,
forbidden,
badRequest,
};| 方法 | 说明 | HTTP 状态码 | success 值 |
|---|---|---|---|
success() |
成功响应 | 200 | true |
error() |
错误响应 | 400 | false |
serverError() |
服务器错误 | 500 | false |
notFound() |
资源不存在 | 404 | false |
unauthorized() |
未授权 | 401 | false |
forbidden() |
禁止访问 | 403 | false |
badRequest() |
请求参数错误 | 400 | false |
基本用法:
const { success } = require("../utils/response");
// 简单成功响应
success(req, res, "操作成功");
// 带数据的成功响应
success(req, res, "获取用户列表成功", {
list: users,
total: 100,
page: 1,
});
// 自定义状态码
success(req, res, "创建成功", { id: 123 }, 201);实际示例(来自 userController.js):
// 获取用户列表
const getUserList = async (req, res) => {
try {
const responseData = {
list: users,
total: totalCount,
page: page,
pageSize: pageSize,
};
success(req, res, "获取用户列表成功", responseData);
} catch (err) {
logger.error("获取用户列表错误", { error: err });
serverError(req, res, "获取用户列表失败");
}
};基本用法:
const { error, badRequest } = require("../utils/response");
// 通用错误响应
error(req, res, "操作失败", 400);
// 带错误数据的响应
error(req, res, "参数验证失败", 400, {
errors: ["用户名不能为空", "密码长度不足"],
});
// 请求参数错误
badRequest(req, res, "请求参数错误", {
field: "username",
message: "用户名格式不正确",
});实际示例:
// 参数验证失败
if (!username || !password) {
return badRequest(req, res, "用户名和密码不能为空");
}
// 业务逻辑错误
if (userExists) {
return error(req, res, "用户名已存在", 400);
}基本用法:
const { serverError } = require("../utils/response");
// 服务器内部错误
try {
await someOperation();
} catch (err) {
logger.error("操作失败", { error: err });
serverError(req, res, "服务器内部错误");
}实际示例:
const createUser = async (req, res) => {
try {
const user = await userModel.createUser(userData);
success(req, res, "用户创建成功", { id: user.id });
} catch (err) {
logger.error("创建用户错误", { error: err });
serverError(req, res, "创建用户失败");
}
};基本用法:
const { unauthorized } = require("../utils/response");
// Token 无效
if (!token || !isValidToken(token)) {
return unauthorized(req, res, "Token 无效或已过期");
}
// 未登录
if (!req.user) {
return unauthorized(req, res, "请先登录");
}基本用法:
const { forbidden } = require("../utils/response");
// 权限不足
if (!hasPermission(req.user, "user:delete")) {
return forbidden(req, res, "您没有删除用户的权限");
}基本用法:
const { notFound } = require("../utils/response");
// 资源不存在
const user = await userModel.getUserById(userId);
if (!user) {
return notFound(req, res, "用户不存在");
}HTTP 状态码:200(默认)或 201、204 等
{
"success": true,
"code": 200,
"message": "操作成功",
"data": {
"id": 123,
"username": "admin"
},
"timestamp": "2024-12-19T10:30:00.000Z"
}HTTP 状态码:400、401、403、404、500 等
{
"success": false,
"code": 400,
"message": "请求参数错误",
"data": {
"field": "username",
"message": "用户名格式不正确"
},
"timestamp": "2024-12-19T10:30:00.000Z"
}| 字段 | 类型 | 说明 | 示例 |
|---|---|---|---|
success |
boolean | 业务成功标识 | true / false |
code |
number | HTTP 状态码 | 200, 400, 500 |
message |
string | 响应消息 | "操作成功" |
data |
any | 响应数据 | {}, [], null |
timestamp |
string | 时间戳(ISO 8601) | "2024-12-19T10:30:00.000Z" |
| 状态码 | 说明 | 使用场景 |
|---|---|---|
200 |
OK | 请求成功(GET、PUT、PATCH) |
201 |
Created | 资源创建成功(POST) |
204 |
No Content | 删除成功,无返回内容(DELETE) |
| 状态码 | 说明 | 使用场景 |
|---|---|---|
400 |
Bad Request | 请求参数错误、业务逻辑错误 |
401 |
Unauthorized | 未授权、Token 无效 |
403 |
Forbidden | 权限不足、禁止访问 |
404 |
Not Found | 资源不存在 |
409 |
Conflict | 资源冲突(如用户名已存在) |
| 状态码 | 说明 | 使用场景 |
|---|---|---|
500 |
Internal Server Error | 服务器内部错误、未捕获的异常 |
const { success, error, notFound, serverError, badRequest } = require("../utils/response");
// 获取用户列表
const getUserList = async (req, res) => {
try {
const { page = 1, pageSize = 10 } = req.query;
const { list, total } = await userModel.getUserList(page, pageSize);
success(req, res, "获取用户列表成功", {
list,
total,
page: parseInt(page),
pageSize: parseInt(pageSize),
});
} catch (err) {
logger.error("获取用户列表错误", { error: err });
serverError(req, res, "获取用户列表失败");
}
};
// 获取用户详情
const getUserById = async (req, res) => {
try {
const { id } = req.params;
const user = await userModel.getUserById(id);
if (!user) {
return notFound(req, res, "用户不存在");
}
success(req, res, "获取用户信息成功", user);
} catch (err) {
logger.error("获取用户信息错误", { error: err });
serverError(req, res, "获取用户信息失败");
}
};
// 创建用户
const createUser = async (req, res) => {
try {
const { username, password, name } = req.body;
// 参数验证
if (!username || !password) {
return badRequest(req, res, "用户名和密码不能为空");
}
// 检查用户名是否存在
const exists = await userModel.checkUsernameExists(username);
if (exists) {
return error(req, res, "用户名已存在", 409);
}
const user = await userModel.createUser({ username, password, name });
success(req, res, "用户创建成功", { id: user.id }, 201);
} catch (err) {
logger.error("创建用户错误", { error: err });
serverError(req, res, "创建用户失败");
}
};
// 更新用户
const updateUser = async (req, res) => {
try {
const { id } = req.params;
const userData = req.body;
const user = await userModel.updateUser(id, userData);
if (!user) {
return notFound(req, res, "用户不存在");
}
success(req, res, "用户更新成功", user);
} catch (err) {
logger.error("更新用户错误", { error: err });
serverError(req, res, "更新用户失败");
}
};
// 删除用户
const deleteUser = async (req, res) => {
try {
const { id } = req.params;
const deleted = await userModel.deleteUser(id);
if (!deleted) {
return notFound(req, res, "用户不存在");
}
success(req, res, "用户删除成功", null);
} catch (err) {
logger.error("删除用户错误", { error: err });
serverError(req, res, "删除用户失败");
}
};const { success, unauthorized, badRequest, serverError } = require("../utils/response");
// 用户登录
const login = async (req, res) => {
try {
const { username, password } = req.body;
if (!username || !password) {
return badRequest(req, res, "用户名和密码不能为空");
}
const user = await userModel.getUserByUsername(username);
if (!user) {
return unauthorized(req, res, "用户名或密码错误");
}
const isValid = await bcrypt.compare(password, user.password);
if (!isValid) {
return unauthorized(req, res, "用户名或密码错误");
}
const token = generateToken(user);
success(req, res, "登录成功", {
token,
user: {
id: user.id,
username: user.username,
name: user.name,
},
});
} catch (err) {
logger.error("登录错误", { error: err });
serverError(req, res, "登录失败");
}
};const { forbidden, unauthorized } = require("../utils/response");
// 权限中间件
const checkPermission = (permission) => {
return async (req, res, next) => {
if (!req.user) {
return unauthorized(req, res, "请先登录");
}
const hasPermission = await permissionService.checkPermission(req.user.id, permission);
if (!hasPermission) {
return forbidden(req, res, `您没有 ${permission} 权限`);
}
next();
};
};系统支持自动设置 X-Requested-Tooltype 响应头(如果请求中包含该请求头):
// 在 sendResponse 函数中
if (req && req.headers && req.headers["x-requested-tooltype"]) {
response.set("X-Requested-Tooltype", req.headers["x-requested-tooltype"]);
}使用场景:用于标识请求来源的工具类型。
好的实践:
success(req, res, "用户创建成功", user);
error(req, res, "用户名已存在,请使用其他用户名", 409);
badRequest(req, res, "请求参数错误:用户名不能为空");不好的实践:
success(req, res, "ok", user); // ❌ 消息不清晰
error(req, res, "error", 400); // ❌ 消息不友好
badRequest(req, res, "bad", null); // ❌ 消息不专业好的实践:
const getUserList = async (req, res) => {
try {
const users = await userModel.getUserList();
success(req, res, "获取用户列表成功", users);
} catch (err) {
logger.error("获取用户列表错误", {
error: err,
stack: err.stack,
query: req.query,
});
serverError(req, res, "获取用户列表失败");
}
};{ list, total, page, pageSize } 格式null 或空对象 {}列表响应示例:
success(req, res, "获取用户列表成功", {
list: users,
total: totalCount,
page: page,
pageSize: pageSize,
});详情响应示例:
success(req, res, "获取用户信息成功", {
id: user.id,
username: user.username,
name: user.name,
// ... 其他字段
});示例:
// GET 请求成功
success(req, res, "获取成功", data); // 默认 200
// POST 请求成功
success(req, res, "创建成功", data, 201);
// 参数错误
badRequest(req, res, "参数错误");
// 未授权
unauthorized(req, res, "Token 无效");
// 权限不足
forbidden(req, res, "权限不足");
// 资源不存在
notFound(req, res, "资源不存在");
// 服务器错误
serverError(req, res, "服务器内部错误");A: 使用 success() 或 error() 方法的第四个参数:
// 成功响应,状态码 201
success(req, res, "创建成功", data, 201);
// 错误响应,状态码 409
error(req, res, "资源冲突", 409, conflictData);A: 传递 null 或空对象:
// 方式1:传递 null
success(req, res, "删除成功", null);
// 方式2:传递空对象
success(req, res, "操作成功", {});A: 使用标准格式:
success(req, res, "获取列表成功", {
list: items,
total: totalCount,
page: page,
pageSize: pageSize,
});A: 包含分页信息:
success(req, res, "获取列表成功", {
list: items,
total: totalCount,
page: parseInt(page),
pageSize: parseInt(pageSize),
totalPages: Math.ceil(totalCount / pageSize),
});A: 使用 data 参数传递错误详情:
error(req, res, "参数验证失败", 400, {
errors: [
{ field: "username", message: "用户名不能为空" },
{ field: "password", message: "密码长度不足" },
],
});标准格式:
{
"success": true,
"code": 200,
"message": "操作成功",
"data": { "id": 123 },
"timestamp": "2024-12-19T10:30:00.000Z"
}列表响应:
{
"success": true,
"code": 200,
"message": "获取列表成功",
"data": {
"list": [...],
"total": 100,
"page": 1,
"pageSize": 10
},
"timestamp": "2024-12-19T10:30:00.000Z"
}参数错误:
{
"success": false,
"code": 400,
"message": "请求参数错误",
"data": {
"field": "username",
"message": "用户名不能为空"
},
"timestamp": "2024-12-19T10:30:00.000Z"
}服务器错误:
{
"success": false,
"code": 500,
"message": "服务器内部错误",
"data": null,
"timestamp": "2024-12-19T10:30:00.000Z"
}统一响应格式提供了:
通过使用统一响应格式,可以:
统一封装响应,确保所有 API 都返回一致的格式