正在加载,请稍候…

使用 Node.js 和 Express 构建 REST API:2026 完整指南

逐步指南,教你使用 Node.js 和 Express 构建生产级 REST API,涵盖路由、中间件、错误处理、验证和部署最佳实践。

使用 Node.js 和 Express 构建 REST API:2026 完整指南

使用 Node.js 和 Express 构建 REST API:2026 完整指南

Node.js + Express 仍然是构建 REST API 最流行的后端技术栈。2026 年,随着 Express 5 稳定版发布和生态系统的成熟,以下是构建快速、可维护且生产就绪 API 的权威指南。

项目设置

mkdir my-api && cd my-api
npm init -y
npm install express
npm install --save-dev typescript @types/express @types/node ts-node nodemon
npx tsc --init

目录结构:

src/
  routes/
    users.ts
    products.ts
  controllers/
    userController.ts
  middleware/
    auth.ts
    errorHandler.ts
  models/
    User.ts
  app.ts
  server.ts

使用 Node.js 和 Express 构建 REST API:2026 完整指南 插图

Express 应用

// src/app.ts
import express, { Application } from 'express';
import userRoutes from './routes/users';
import { errorHandler } from './middleware/errorHandler';
import { notFound } from './middleware/notFound';

const app: Application = express();

// 内置中间件
app.use(express.json());
app.use(express.urlencoded({ extended: true }));

// 路由
app.use('/api/users', userRoutes);

// 404 处理(必须在路由之后)
app.use(notFound);

// 错误处理(必须在最后)
app.use(errorHandler);

export default app;
// src/server.ts
import app from './app';

const PORT = process.env.PORT || 3000;

app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});

RESTful 路由

// src/routes/users.ts
import { Router } from 'express';
import {
  getUsers,
  getUserById,
  createUser,
  updateUser,
  deleteUser,
} from '../controllers/userController';
import { authenticate } from '../middleware/auth';
import { validateUser } from '../middleware/validate';

const router = Router();

router.get('/', authenticate, getUsers);
router.get('/:id', authenticate, getUserById);
router.post('/', validateUser, createUser);
router.put('/:id', authenticate, validateUser, updateUser);
router.delete('/:id', authenticate, deleteUser);

export default router;

控制器

// src/controllers/userController.ts
import { Request, Response, NextFunction } from 'express';
import { UserService } from '../services/userService';

const userService = new UserService();

export async function getUsers(req: Request, res: Response, next: NextFunction) {
  try {
    const { page = 1, limit = 20 } = req.query;
    const users = await userService.findAll({
      page: Number(page),
      limit: Number(limit),
    });
    res.json({
      success: true,
      data: users,
      meta: { page: Number(page), limit: Number(limit) },
    });
  } catch (error) {
    next(error); // 传递给错误处理
  }
}

export async function getUserById(req: Request, res: Response, next: NextFunction) {
  try {
    const user = await userService.findById(req.params.id);
    if (!user) {
      return res.status(404).json({ success: false, message: 'User not found' });
    }
    res.json({ success: true, data: user });
  } catch (error) {
    next(error);
  }
}

export async function createUser(req: Request, res: Response, next: NextFunction) {
  try {
    const user = await userService.create(req.body);
    res.status(201).json({ success: true, data: user });
  } catch (error) {
    next(error);
  }
}

中间件

认证中间件

// src/middleware/auth.ts
import { Request, Response, NextFunction } from 'express';
import jwt from 'jsonwebtoken';

interface JwtPayload {
  userId: string;
  email: string;
}

// 扩展 Request 类型
declare global {
  namespace Express {
    interface Request {
      user?: JwtPayload;
    }
  }
}

export function authenticate(req: Request, res: Response, next: NextFunction) {
  const token = req.headers.authorization?.split(' ')[1]; // Bearer TOKEN

  if (!token) {
    return res.status(401).json({ success: false, message: 'No token provided' });
  }

  try {
    const decoded = jwt.verify(token, process.env.JWT_SECRET!) as JwtPayload;
    req.user = decoded;
    next();
  } catch {
    res.status(401).json({ success: false, message: 'Invalid token' });
  }
}

使用 Node.js 和 Express 构建 REST API:2026 完整指南 插图

验证中间件(使用 Zod)

// src/middleware/validate.ts
import { z } from 'zod';
import { Request, Response, NextFunction } from 'express';

const userSchema = z.object({
  name: z.string().min(2).max(50),
  email: z.string().email(),
  password: z.string().min(8),
  role: z.enum(['user', 'admin']).optional().default('user'),
});

export function validateUser(req: Request, res: Response, next: NextFunction) {
  const result = userSchema.safeParse(req.body);
  if (!result.success) {
    return res.status(400).json({
      success: false,
      message: 'Validation failed',
      errors: result.error.flatten().fieldErrors,
    });
  }
  req.body = result.data; // 使用解析/强制转换后的数据
  next();
}

全局错误处理

// src/middleware/errorHandler.ts
import { Request, Response, NextFunction } from 'express';

export class AppError extends Error {
  constructor(
    public message: string,
    public statusCode: number = 500,
    public isOperational: boolean = true
  ) {
    super(message);
    Object.setPrototypeOf(this, AppError.prototype);
  }
}

export function errorHandler(
  err: Error,
  req: Request,
  res: Response,
  next: NextFunction
) {
  if (err instanceof AppError) {
    return res.status(err.statusCode).json({
      success: false,
      message: err.message,
    });
  }

  // 意外错误——在生产环境中记录并隐藏细节
  console.error(err);
  res.status(500).json({
    success: false,
    message: process.env.NODE_ENV === 'production'
      ? 'Internal server error'
      : err.message,
  });
}

REST API 最佳实践

使用一致的响应格式

// 成功
{ "success": true, "data": { ... }, "meta": { "page": 1, "total": 100 } }

// 错误
{ "success": false, "message": "User not found", "errors": { "email": ["Invalid format"] } }

HTTP 状态码

场景 状态码
成功 (GET) 200 OK
已创建 (POST) 201 Created
无内容 (DELETE) 204 No Content
错误请求 400 Bad Request
未授权 401 Unauthorized
禁止 403 Forbidden
未找到 404 Not Found
验证错误 422 Unprocessable Entity
服务器错误 500 Internal Server Error

使用 Node.js 和 Express 构建 REST API:2026 完整指南 插图

分页模式

// GET /api/users?page=2&limit=20&sort=createdAt&order=desc
router.get('/', async (req, res) => {
  const { page = 1, limit = 20, sort = 'createdAt', order = 'desc' } = req.query;
  
  const skip = (Number(page) - 1) * Number(limit);
  const [users, total] = await Promise.all([
    User.find().sort({ [sort as string]: order as 'asc' | 'desc' }).skip(skip).limit(Number(limit)),
    User.countDocuments()
  ]);

  res.json({
    success: true,
    data: users,
    meta: {
      page: Number(page),
      limit: Number(limit),
      total,
      totalPages: Math.ceil(total / Number(limit))
    }
  });
});

速率限制与安全

npm install express-rate-limit helmet cors
import rateLimit from 'express-rate-limit';
import helmet from 'helmet';
import cors from 'cors';

// 安全头
app.use(helmet());

// CORS
app.use(cors({
  origin: process.env.ALLOWED_ORIGINS?.split(',') || 'http://localhost:3000',
  credentials: true,
}));

// 速率限制:每 15 分钟 100 次请求
const limiter = rateLimit({
  windowMs: 15 * 60 * 1000,
  max: 100,
  standardHeaders: true,
  legacyHeaders: false,
  message: { success: false, message: 'Too many requests, please try again later.' },
});
app.use('/api/', limiter);

环境变量

# .env
PORT=3000
NODE_ENV=development
JWT_SECRET=your-super-secret-key-here
DATABASE_URL=postgresql://user:password@localhost:5432/mydb
ALLOWED_ORIGINS=http://localhost:5173,https://myapp.com
// 使用 dotenv 加载
import dotenv from 'dotenv';
dotenv.config(); // 必须在访问 process.env 之前调用

测试你的 API

# 使用 curl 快速测试
curl -X GET http://localhost:3000/api/users
curl -X POST http://localhost:3000/api/users \
  -H "Content-Type: application/json" \
  -d '{"name":"John","email":"john@example.com","password":"secret123"}'

# 带认证令牌
curl -X GET http://localhost:3000/api/users \
  -H "Authorization: Bearer eyJhbGci..."

总结

生产级 Node.js API 的关键要点:

  1. 分离关注点:路由 → 控制器 → 服务 → 模型
  2. 始终使用中间件 处理认证、验证和错误
  3. 全局错误处理 捕获所有异常——不要让错误溜走
  4. 验证所有输入,使用 Zod 或 Joi 进行处理前验证
  5. 使用环境变量——永远不要硬编码密钥
  6. 添加速率限制和安全头,在上线前完成
  7. 一致的响应格式 使客户端代码更简单

→ 使用 JSON Viewer 测试你的 API 响应,使用 JWT Parser 解析 JWT。