名称:后端服务模式 描述:使用分层架构、依赖注入、中间件模式、服务类和关注点分离来构建可扩展的后端服务。适用于构建API服务、实现业务逻辑层、创建服务类、设置中间件链、实施依赖注入、设计控制器-服务-仓库模式、处理横切关注点、创建领域模型、实现CQRS模式或建立后端架构标准。
后端服务模式 - 构建可扩展的服务器应用
何时使用此技能
- 构建API服务和后端应用
- 在服务层实现业务逻辑
- 创建控制器-服务-仓库架构
- 设置Express/Fastify中间件链
- 实现依赖注入容器
- 设计领域模型和业务实体
- 处理横切关注点(日志记录、认证、验证)
- 实现CQRS(命令查询责任分离)
- 创建后台作业处理服务
- 设计事件驱动的服务架构
- 实现API网关模式
- 构建具有清晰边界的微服务
何时使用此技能
- 设计后端架构、实现API、处理业务逻辑、管理微服务或构建无服务器函数。
- 当处理相关任务或功能时
- 在需要此专业知识的开发过程中
使用时机:设计后端架构、实现API、处理业务逻辑、管理微服务或构建无服务器函数。
核心原则
- 关注点分离 - 层之间有清晰边界
- 单一职责 - 每个服务做好一件事
- 无状态设计 - 易于水平扩展
- 幂等性 - 操作可安全重试
- 快速失败,优雅恢复 - 显式处理错误
分层架构
1. 三层架构
// ✅ 路由层 - HTTP端点
// routes/users.ts
import express from 'express';
import { UserController } from '../controllers/UserController';
const router = express.Router();
const userController = new UserController();
router.get('/users', userController.list);
router.post('/users', userController.create);
router.get('/users/:id', userController.get);
export default router;
// ✅ 控制器层 - 请求/响应处理
// controllers/UserController.ts
import { Request, Response } from 'express';
import { UserService } from '../services/UserService';
import { CreateUserSchema } from '../schemas/user';
export class UserController {
private userService = new UserService();
list = async (req: Request, res: Response) => {
try {
const users = await this.userService.listUsers({
page: parseInt(req.query.page as string) || 1,
limit: parseInt(req.query.limit as string) || 20
});
res.json(users);
} catch (error) {
res.status(500).json({ error: '获取用户失败' });
}
};
create = async (req: Request, res: Response) => {
try {
const validated = CreateUserSchema.parse(req.body);
const user = await this.userService.createUser(validated);
res.status(201).json(user);
} catch (error) {
res.status(400).json({ error: error.message });
}
};
}
// ✅ 服务层 - 业务逻辑
// services/UserService.ts
import { UserRepository } from '../repositories/UserRepository';
import { EmailService } from './EmailService';
export class UserService {
private userRepo = new UserRepository();
private emailService = new EmailService();
async createUser(data: CreateUserInput) {
// 业务逻辑在此
const existingUser = await this.userRepo.findByEmail(data.email);
if (existingUser) {
throw new Error('邮箱已存在');
}
const hashedPassword = await bcrypt.hash(data.password, 10);
const user = await this.userRepo.create({
...data,
passwordHash: hashedPassword
});
// 异步发送欢迎邮件
await this.emailService.sendWelcome(user.email);
return user;
}
async listUsers(params: { page: number; limit: number }) {
return await this.userRepo.findMany({
skip: (params.page - 1) * params.limit,
take: params.limit
});
}
}
// ✅ 仓库层 - 数据访问
// repositories/UserRepository.ts
import { prisma } from '../db';
export class UserRepository {
async create(data: CreateUserData) {
return await prisma.user.create({ data });
}
async findByEmail(email: string) {
return await prisma.user.findUnique({ where: { email } });
}
async findMany(params: { skip: number; take: number }) {
return await prisma.user.findMany(params);
}
}
2. 依赖注入
// ✅ 构造函数注入以提高可测试性
export class OrderService {
constructor(
private orderRepo: OrderRepository,
private paymentService: PaymentService,
private emailService: EmailService
) {}
async processOrder(orderId: string) {
const order = await this.orderRepo.findById(orderId);
const payment = await this.paymentService.charge(order);
await this.emailService.sendReceipt(order, payment);
return payment;
}
}
// 易于在测试中模拟
const mockOrderRepo = {
findById: jest.fn().mockResolvedValue({ id: '1', total: 100 })
};
const mockPaymentService = {
charge: jest.fn().mockResolvedValue({ id: 'pay_123' })
};
const service = new OrderService(mockOrderRepo, mockPaymentService, mockEmailService);
设计模式
1. 仓库模式
// ✅ 通过接口抽象数据访问
interface IUserRepository {
create(data: CreateUserData): Promise<User>;
findById(id: string): Promise<User | null>;
update(id: string, data: UpdateUserData): Promise<User>;
delete(id: string): Promise<void>;
}
// PostgreSQL实现
export class PostgresUserRepository implements IUserRepository {
async create(data: CreateUserData) {
return await prisma.user.create({ data });
}
async findById(id: string) {
return await prisma.user.findUnique({ where: { id } });
}
// ... 其他方法
}
// MongoDB实现(易于交换)
export class MongoUserRepository implements IUserRepository {
async create(data: CreateUserData) {
return await User.create(data);
}
// ... 其他方法
}
2. 服务层模式
// ✅ 封装业务逻辑
export class OrderService {
async placeOrder(userId: string, items: OrderItem[]) {
// 验证库存
for (const item of items) {
const product = await this.productRepo.findById(item.productId);
if (product.stock < item.quantity) {
throw new InsufficientStockError(item.productId);
}
}
// 计算总额
const total = items.reduce((sum, item) => sum + item.price * item.quantity, 0);
// 应用折扣
const discount = await this.discountService.calculateDiscount(userId, total);
// 创建订单
const order = await this.orderRepo.create({
userId,
items,
subtotal: total,
discount,
total: total - discount,
status: 'pending'
});
// 预留库存
for (const item of items) {
await this.inventoryService.reserve(item.productId, item.quantity);
}
// 排队支付处理
await this.paymentQueue.add({ orderId: order.id });
return order;
}
}
3. 工厂模式
// ✅ 基于条件创建对象
interface PaymentProvider {
charge(amount: number, currency: string): Promise<PaymentResult>;
}
class StripeProvider implements PaymentProvider {
async charge(amount: number, currency: string) {
return await stripe.charges.create({ amount, currency });
}
}
class PayPalProvider implements PaymentProvider {
async charge(amount: number, currency: string) {
return await paypal.payment.create({ amount, currency });
}
}
class PaymentProviderFactory {
static create(provider: string): PaymentProvider {
switch (provider) {
case 'stripe':
return new StripeProvider();
case 'paypal':
return new PayPalProvider();
default:
throw new Error(`未知提供者:${provider}`);
}
}
}
// 使用
const provider = PaymentProviderFactory.create(user.preferredPaymentMethod);
await provider.charge(100, 'USD');
4. 策略模式
// ✅ 运行时交换算法
interface ShippingStrategy {
calculateCost(weight: number, distance: number): number;
}
class StandardShipping implements ShippingStrategy {
calculateCost(weight: number, distance: number) {
return weight * 0.5 + distance * 0.1;
}
}
class ExpressShipping implements ShippingStrategy {
calculateCost(weight: number, distance: number) {
return weight * 1.0 + distance * 0.3;
}
}
class OvernightShipping implements ShippingStrategy {
calculateCost(weight: number, distance: number) {
return weight * 2.0 + distance * 0.5;
}
}
class ShippingCalculator {
constructor(private strategy: ShippingStrategy) {}
calculate(weight: number, distance: number) {
return this.strategy.calculateCost(weight, distance);
}
}
// 使用
const calculator = new ShippingCalculator(new ExpressShipping());
const cost = calculator.calculate(10, 500);
5. 观察者模式(事件驱动)
// ✅ 通过事件解耦组件
import { EventEmitter } from 'events';
class OrderEvents extends EventEmitter {
static CREATED = 'order.created';
static PAID = 'order.paid';
static SHIPPED = 'order.shipped';
static CANCELLED = 'order.cancelled';
}
const orderEvents = new OrderEvents();
// 监听器
orderEvents.on(OrderEvents.CREATED, async (order) => {
await emailService.sendOrderConfirmation(order);
await analyticsService.trackOrderCreated(order);
});
orderEvents.on(OrderEvents.PAID, async (order) => {
await inventoryService.deductStock(order.items);
await shippingService.createShipment(order);
});
// 发出事件
export class OrderService {
async createOrder(data: CreateOrderData) {
const order = await this.orderRepo.create(data);
orderEvents.emit(OrderEvents.CREATED, order);
return order;
}
async markAsPaid(orderId: string) {
const order = await this.orderRepo.update(orderId, { status: 'paid' });
orderEvents.emit(OrderEvents.PAID, order);
return order;
}
}
微服务模式
1. API网关
// ✅ 多个服务的单一入口点
import express from 'express';
import { createProxyMiddleware } from 'http-proxy-middleware';
const app = express();
// 路由到不同服务
app.use('/api/users', createProxyMiddleware({
target: 'http://user-service:3001',
changeOrigin: true
}));
app.use('/api/orders', createProxyMiddleware({
target: 'http://order-service:3002',
changeOrigin: true
}));
app.use('/api/payments', createProxyMiddleware({
target: 'http://payment-service:3003',
changeOrigin: true
}));
// 在此添加认证、速率限制、日志记录
app.use(authMiddleware);
app.use(rateLimiter);
app.use(logger);
2. 服务间通信
// ✅ HTTP/REST通信
export class UserService {
private orderServiceUrl = process.env.ORDER_SERVICE_URL;
async getUserWithOrders(userId: string) {
const user = await this.userRepo.findById(userId);
// 调用订单服务
const response = await fetch(`${this.orderServiceUrl}/orders?userId=${userId}`);
const orders = await response.json();
return { ...user, orders };
}
}
// ✅ 消息队列通信(异步)
import { Queue } from 'bullmq';
const emailQueue = new Queue('emails', {
connection: { host: 'redis', port: 6379 }
});
// 生产者(用户服务)
export class UserService {
async createUser(data: CreateUserData) {
const user = await this.userRepo.create(data);
// 异步通知
await emailQueue.add('welcome', {
userId: user.id,
email: user.email
});
return user;
}
}
// 消费者(邮件服务)
import { Worker } from 'bullmq';
const worker = new Worker('emails', async (job) => {
if (job.name === 'welcome') {
await sendWelcomeEmail(job.data.email);
}
});
3. 熔断器模式
// ✅ 防止级联故障
import CircuitBreaker from 'opossum';
const options = {
timeout: 3000, // 如果函数耗时 > 3秒,触发失败
errorThresholdPercentage: 50, // 当50%的请求失败时...
resetTimeout: 30000 // ...打开电路30秒
};
const breaker = new CircuitBreaker(callExternalAPI, options);
breaker.fallback(() => {
return { data: null, fromCache: true }; // 后备响应
});
breaker.on('open', () => {
console.log('熔断器打开 - 太多失败');
});
async function callExternalAPI() {
const response = await fetch('https://external-api.com/data');
return response.json();
}
// 使用
try {
const data = await breaker.fire();
} catch (error) {
// 电路打开或请求失败
}
无服务器模式
1. 函数即服务
// ✅ AWS Lambda处理程序
import { APIGatewayProxyHandler } from 'aws-lambda';
export const handler: APIGatewayProxyHandler = async (event) => {
try {
const body = JSON.parse(event.body || '{}');
// 业务逻辑
const result = await processOrder(body);
return {
statusCode: 200,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
},
body: JSON.stringify(result)
};
} catch (error) {
return {
statusCode: 500,
body: JSON.stringify({ error: error.message })
};
}
};
// ✅ Vercel边缘函数
export const config = {
runtime: 'edge'
};
export default async function handler(request: Request) {
const data = await processData();
return new Response(JSON.stringify(data), {
headers: { 'content-type': 'application/json' }
});
}
2. 冷启动优化
// ✅ 在处理程序外部初始化(在热调用中持久化)
import { PrismaClient } from '@prisma/client';
// 创建一次,在热调用中重用
const prisma = new PrismaClient();
export const handler = async (event) => {
// 这在每次调用时运行
const users = await prisma.user.findMany();
return { statusCode: 200, body: JSON.stringify(users) };
};
// ✅ 懒初始化
let connection: Connection | null = null;
async function getConnection() {
if (!connection) {
connection = await createConnection();
}
return connection;
}
export const handler = async (event) => {
const conn = await getConnection();
// 使用连接
};
后台作业
1. 作业队列模式
// ✅ BullMQ作业处理
import { Queue, Worker } from 'bullmq';
const videoQueue = new Queue('video-processing', {
connection: { host: 'redis', port: 6379 }
});
// 添加作业
export class VideoService {
async uploadVideo(file: File) {
const video = await this.videoRepo.create({
filename: file.name,
status: 'pending'
});
// 排队处理作业
await videoQueue.add('transcode', {
videoId: video.id,
inputPath: file.path
}, {
attempts: 3, // 重试最多3次
backoff: {
type: 'exponential',
delay: 5000 // 5秒, 10秒, 20秒
}
});
return video;
}
}
// 工作进程
const worker = new Worker('video-processing', async (job) => {
if (job.name === 'transcode') {
await transcodeVideo(job.data.videoId, job.data.inputPath);
// 更新进度
job.updateProgress(50);
await generateThumbnail(job.data.videoId);
job.updateProgress(100);
}
}, {
connection: { host: 'redis', port: 6379 },
concurrency: 5 // 并发处理5个作业
});
worker.on('completed', (job) => {
console.log(`作业 ${job.id} 完成`);
});
worker.on('failed', (job, err) => {
console.error(`作业 ${job.id} 失败:`, err);
});
2. 定时任务
// ✅ 使用node-cron的定时任务
import cron from 'node-cron';
// 每天午夜运行
cron.schedule('0 0 * * *', async () => {
await cleanupExpiredSessions();
await generateDailyReport();
});
// 每5分钟运行
cron.schedule('*/5 * * * *', async () => {
await checkPaymentStatus();
});
// ✅ 或使用BullMQ重复
await queue.add('daily-report', {}, {
repeat: {
pattern: '0 0 * * *' // Cron表达式
}
});
后端最佳实践
1. 配置管理
// ✅ 基于环境的配置
export const config = {
port: parseInt(process.env.PORT || '3000'),
database: {
url: process.env.DATABASE_URL,
poolSize: parseInt(process.env.DB_POOL_SIZE || '10')
},
redis: {
host: process.env.REDIS_HOST || 'localhost',
port: parseInt(process.env.REDIS_PORT || '6379')
},
jwt: {
secret: process.env.JWT_SECRET,
expiresIn: '1h'
}
};
// 启动时验证必需变量
const required = ['DATABASE_URL', 'JWT_SECRET'];
for (const key of required) {
if (!process.env[key]) {
throw new Error(`缺少必需环境变量:${key}`);
}
}
2. 健康检查
// ✅ 健康检查端点
app.get('/health', async (req, res) => {
const health = {
uptime: process.uptime(),
timestamp: Date.now(),
status: 'ok',
checks: {
database: 'ok',
redis: 'ok'
}
};
try {
await prisma.$queryRaw`SELECT 1`;
} catch (error) {
health.status = 'degraded';
health.checks.database = 'error';
}
try {
await redis.ping();
} catch (error) {
health.status = 'degraded';
health.checks.redis = 'error';
}
const statusCode = health.status === 'ok' ? 200 : 503;
res.status(statusCode).json(health);
});
后端服务清单
架构:
□ 关注点分离清晰(路由/控制器/服务/仓库)
□ 依赖注入以提高可测试性
□ 业务逻辑在服务层(不在控制器中)
□ 数据访问抽象在仓库中
□ 控制器中无数据库查询
API设计:
□ RESTful端点
□ 正确的HTTP方法和状态码
□ 所有端点的输入验证
□ 列表分页
□ API版本控制策略
错误处理:
□ 所有异步函数中使用try/catch
□ 有意义的错误消息
□ 正确的错误状态码
□ 带上下文的错误日志记录
□ 错误响应中无敏感数据
性能:
□ 数据库查询优化
□ 连接池配置
□ 缓存策略实施
□ 后台作业用于重操作
□ 公共端点的速率限制
安全:
□ 必需认证
□ 授权检查
□ 输入清理
□ SQL注入预防
□ CORS配置正确
监控:
□ 健康检查端点
□ 日志记录配置
□ 指标收集
□ 错误跟踪(Sentry等)
□ 性能监控
资源
记住:优秀的后端服务是可维护、可测试、可扩展和弹性的。为失败设计,优化可读性。