后端架构模式、API设计、数据库优化以及适用于Node.js、Express和Next.js API路由的服务器端最佳实践。
name backend-patterns description 后端架构模式、API设计、数据库优化以及适用于Node.js、Express和Next.js API路由的服务器端最佳实践。 origin ECC 后端开发模式 用于可扩展服务器端应用程序的后端架构模式和最佳实践。 何时激活 设计 REST 或 GraphQL API 端点时 实现仓储层、服务层或控制器层时 优化数据库查询(N+1问题、索引、连接池)时 添加缓存(Redis、内存缓存、HTTP 缓存头)时 设置后台作业或异步处理时 为 API 构建错误处理和验证结构时 构建中间件(认证、日志记录、速率限制)时 API 设计模式 RESTful API 结构 // PASS: Resource-based URLs GET /api/markets # List resources GET /api/markets/:id # Get single resource POST /api/markets # Create resource PUT /api/markets/:id # Replace resource PATCH /api/markets/:id # Update resource DELETE /api/markets/:id # Delete resource // PASS: Query parameters for filtering, sorting, pagination GET /api/markets?status=active&sort=volume&limit= 20 &offset= 0 仓储模式 // Abstract data access logic interface MarketRepository { findAll ( filters ?: MarketFilters ): Promise < Market []> findById ( id : string ): Promise < Market | null
create ( data : CreateMarketDto ): Promise < Market
update ( id : string , data : UpdateMarketDto ): Promise < Market
delete ( id : string ): Promise < void
await getUser (market. creator_id ) // N queries } // PASS: GOOD: Batch fetch const markets = await getMarkets () const creatorIds = markets. map ( m => m. creator_id ) const creators = await getUsers (creatorIds) // 1 query const creatorMap = new Map (creators. map ( c => [c. id , c]))
Rollback happens automatically RETURN jsonb_build_object ( 'success' , false , 'error' , SQLERRM ); END ; $; 缓存策略 Redis 缓存层 class CachedMarketRepository implements MarketRepository { constructor ( private baseRepo : MarketRepository , private redis : RedisClient ) {} async findById ( id : string ): Promise < Market | null
{ // Check cache first const cached = await this . redis . get (
market: ${id}) if (cached) { return JSON . parse (cached) } // Cache miss - fetch from database const market = await this . baseRepo . findById (id) if (market) { // Cache for 5 minutes await this . redis . setex (market: ${id}, 300 , JSON . stringify (market)) } return market } async invalidateCache ( id : string ): Promise < void { await this . redis . del (market: ${id}) } } 旁路缓存模式 async function getMarketWithCache ( id : string ): Promise < Market { const cacheKey =market: ${id}// Try cache const cached = await redis. get (cacheKey) if (cached) return JSON . parse (cached) // Cache miss - fetch from DB const market = await db. markets . findUnique ({ where : { id } }) if (!market) throw new Error ( 'Market not found' ) // Update cache await redis. setex (cacheKey, 300 , JSON . stringify (market)) return market } 错误处理模式 集中式错误处理程序 class ApiError extends Error { constructor ( public statusCode : number , public message : string , public isOperational = true ) { super (message) Object . setPrototypeOf ( this , ApiError . prototype ) } } export function errorHandler ( error : unknown , req : Request ): Response { if (error instanceof ApiError ) { return NextResponse . json ({ success : false , error : error. message }, { status : error. statusCode }) } if (error instanceof z. ZodError ) { return NextResponse . json ({ success : false , error : 'Validation failed' , details : error. errors }, { status : 400 }) } // Log unexpected errors console . error ( 'Unexpected error:' , error) return NextResponse . json ({ success : false , error : 'Internal server error' }, { status : 500 }) } // Usage export async function GET ( request : Request ) { try { const data = await fetchData () return NextResponse . json ({ success : true , data }) } catch (error) { return errorHandler (error, request) } } 指数退避重试 async function fetchWithRetry<T>( fn : () => Promise <T>, maxRetries = 3 ): Promise <T> { let lastError : Error for ( let i = 0 ; i < maxRetries; i++) { try { return await fn () } catch (error) { lastError = error as Error if (i < maxRetries - 1 ) { // Exponential backoff: 1s, 2s, 4s const delay = Math . pow ( 2 , i) * 1000 await new Promise ( resolve => setTimeout (resolve, delay)) } } } throw lastError! } // Usage const data = await fetchWithRetry ( () => fetchFromAPI ()) 认证与授权 JWT 令牌验证 import jwt from 'jsonwebtoken' interface JWTPayload { userId : string email : string role : 'admin' | 'user' } export function verifyToken ( token : string ): JWTPayload { try { const payload = jwt. verify (token, process. env . JWT_SECRET !) as JWTPayload return payload } catch (error) { throw new ApiError ( 401 , 'Invalid token' ) } } export async function requireAuth ( request : Request ) { const token = request. headers . get ( 'authorization' )?. replace ( 'Bearer ' , '' ) if (!token) { throw new ApiError ( 401 , 'Missing authorization token' ) } return verifyToken (token) } // Usage in API route export async function GET ( request : Request ) { const user = await requireAuth (request) const data = await getDataForUser (user. userId ) return NextResponse . json ({ success : true , data }) } 基于角色的访问控制 type Permission = 'read' | 'write' | 'delete' | 'admin' interface User { id : string role : 'admin' | 'moderator' | 'user' } const rolePermissions : Record < User [ 'role' ], Permission []> = { admin : [ 'read' , 'write' , 'delete' , 'admin' ], moderator : [ 'read' , 'write' , 'delete' ], user : [ 'read' , 'write' ] } export function hasPermission ( user : User , permission : Permission ): boolean { return rolePermissions[user. role ]. includes (permission) } export function requirePermission ( permission : Permission ) { return ( handler : (request: Request, user: User) => Promise < Response
requirePermission ( 'delete' )( async ( request : Request , user : User ) => { // Handler receives authenticated user with verified permission return new Response ( 'Deleted' , { status : 200 }) } ) 速率限制 简单的内存速率限制器 class RateLimiter { private requests = new Map < string , number []>() async checkLimit ( identifier : string , maxRequests : number , windowMs : number ): Promise < boolean
{ const now = Date . now () const requests = this . requests . get (identifier) || [] // Remove old requests outside window const recentRequests = requests. filter ( time => now - time < windowMs) if (recentRequests. length = maxRequests) { return false // Rate limit exceeded } // Add current request recentRequests. push (now) this . requests . set (identifier, recentRequests) return true } } const limiter = new RateLimiter () export async function GET ( request : Request ) { const ip = request. headers . get ( 'x-forwarded-for' ) || 'unknown' const allowed = await limiter. checkLimit (ip, 100 , 60000 ) // 100 req/min if (!allowed) { return NextResponse . json ({ error : 'Rate limit exceeded' }, { status : 429 }) } // Continue with request } 后台作业与队列 简单队列模式 class JobQueue <T> { private queue : T[] = [] private processing = false async add ( job : T): Promise < void { this . queue . push (job) if (! this . processing ) { this . process () } } private async process (): Promise < void { this . processing = true while ( this . queue . length
false } private async execute ( job : T): Promise < void
{ // Job execution logic } } // Usage for indexing markets interface IndexJob { marketId : string } const indexQueue = new JobQueue < IndexJob () export async function POST ( request : Request ) { const { marketId } = await request. json () // Add to queue instead of blocking await indexQueue. add ({ marketId }) return NextResponse . json ({ success : true , message : 'Job queued' }) } 日志记录与监控 结构化日志记录 interface LogContext { userId ?: string requestId ?: string method ?: string path ?: string [ key : string ]: unknown } class Logger { log ( level : 'info' | 'warn' | 'error' , message : string , context ?: LogContext ) { const entry = { timestamp : new Date (). toISOString (), level, message, ...context } console . log ( JSON . stringify (entry)) } info ( message : string , context ?: LogContext ) { this . log ( 'info' , message, context) } warn ( message : string , context ?: LogContext ) { this . log ( 'warn' , message, context) } error ( message : string , error : Error , context ?: LogContext ) { this . log ( 'error' , message, { ...context, error : error. message , stack : error. stack }) } } const logger = new Logger () // Usage export async function GET ( request : Request ) { const requestId = crypto. randomUUID ()
logger. info ( 'Fetching markets' , { requestId, method : 'GET' , path : '/api/markets' }) try { const markets = await fetchMarkets () return NextResponse . json ({ success : true , data : markets }) } catch (error) { logger. error ( 'Failed to fetch markets' , error as Error , { requestId }) return NextResponse . json ({ error : 'Internal error' }, { status : 500 }) } } 记住 :后端模式支持可扩展、可维护的服务器端应用程序。选择适合你复杂程度的模式。
Django架构模式,使用DRF设计REST API,ORM最佳实践,缓存,信号,中间件,以及生产级Django应用程序。