代码组织与架构演进策略
代码组织与架构演进策略
Koa2作为Node.js生态中轻量级的Web框架,其洋葱圈模型和异步中间件机制为应用架构提供了灵活的基础。但随着业务复杂度提升,如何组织代码并规划架构演进路径成为关键问题。以下从目录结构设计、中间件分层、插件化扩展等维度展开具体实践方案。
基础目录结构设计
典型的Koa2项目初期常采用功能维度划分:
/src
/controllers
/models
/routes
/middlewares
app.js
当路由超过20个时,建议切换为业务模块划分:
/src
/modules
/user
user.controller.js
user.model.js
user.router.js
/order
order.controller.js
order.model.js
order.router.js
/core
/middlewares
/services
app.js
通过动态加载实现路由自动化注册:
// app.js
const fs = require('fs')
const path = require('path')
fs.readdirSync('./src/modules').forEach(module => {
const router = require(`./modules/${module}/${module}.router`)
app.use(router.routes())
})
中间件的分层策略
基础设施层中间件
处理HTTP基础能力,建议执行顺序:
app.use(require('koa-helmet')()) // 安全头
app.use(require('koa-compress')()) // 压缩
app.use(require('koa-bodyparser')()) // 体解析
业务逻辑层中间件
实现具体业务规则,典型模式:
// 订单状态校验中间件
async function orderStatusValidator(ctx, next) {
const order = await OrderService.getById(ctx.params.id)
if (order.status !== 'paid') {
ctx.throw(403, '订单未支付')
}
ctx.state.order = order // 挂载到上下文
await next()
}
// 路由中使用
router.post('/refund',
orderStatusValidator,
async ctx => {
await RefundService.create(ctx.state.order)
}
)
插件化架构演进
当需要支持多租户时,可通过插件机制改造:
// plugins/tenant/index.js
module.exports = function tenantPlugin(app) {
app.context.getTenantDB = function() {
return this.headers['x-tenant-id']
? getTenantConnection(this.headers['x-tenant-id'])
: defaultDB
}
app.use(async (ctx, next) => {
ctx.db = ctx.getTenantDB()
await next()
})
}
// app.js
const tenant = require('./plugins/tenant')
tenant(app)
配置管理的进阶方案
从基础配置到动态配置的演进:
// config/default.js
module.exports = {
db: {
host: process.env.DB_HOST || 'localhost',
pool: {
max: process.env.NODE_ENV === 'production' ? 20 : 5
}
}
}
// 动态配置加载器
class ConfigLoader {
constructor() {
this._config = require('./config/default')
this.watchFile()
}
watchFile() {
fs.watch('./config', (event, filename) => {
if (filename.endsWith('.js')) {
this._config = require('./config/' + filename)
}
})
}
get config() {
return this._config
}
}
异常处理体系构建
分级错误处理机制示例:
// core/error.js
class BusinessError extends Error {
constructor(code, message) {
super(message)
this.code = code
}
}
// 中间件处理
app.use(async (ctx, next) => {
try {
await next()
} catch (err) {
if (err instanceof BusinessError) {
ctx.status = 400
ctx.body = { code: err.code, msg: err.message }
} else {
ctx.status = 500
ctx.body = { code: 'SERVER_ERROR', msg: '系统异常' }
ctx.app.emit('error', err, ctx) // 触发日志记录
}
}
})
// 业务中使用
router.post('/create', async ctx => {
if (!ctx.request.body.name) {
throw new BusinessError('INVALID_PARAM', '名称不能为空')
}
})
性能优化架构调整
针对高并发场景的架构改造:
// 引入路由级缓存
const LRU = require('lru-cache')
const productCache = new LRU({
max: 1000,
maxAge: 1000 * 60 * 5 // 5分钟
})
router.get('/products/:id',
async (ctx, next) => {
const cached = productCache.get(ctx.params.id)
if (cached) {
ctx.body = cached
return
}
await next()
},
async ctx => {
const product = await ProductService.getDetail(ctx.params.id)
productCache.set(ctx.params.id, product)
ctx.body = product
}
)
// 数据库连接池优化
const knex = require('knex')({
client: 'mysql2',
connection: {
pool: {
afterCreate: (conn, done) => {
conn.query('SET SESSION wait_timeout = 28800', done)
}
}
}
})
微服务化演进路径
逐步拆分的过渡方案:
// gateway/proxy.js
const httpProxy = require('http-proxy-middleware')
module.exports = function(serviceName) {
return async (ctx, next) => {
if (ctx.path.startsWith(`/api/${serviceName}`)) {
return httpProxy({
target: `http://${serviceName}-service:3000`,
pathRewrite: { [`^/api/${serviceName}`]: '' },
changeOrigin: true
})(ctx.req, ctx.res, next)
}
await next()
}
}
// app.js
app.use(require('./gateway/proxy')('user'))
app.use(require('./gateway/proxy')('order'))
类型系统的引入
逐步接入TypeScript的混合方案:
// ts-check.js
const { execSync } = require('child_process')
module.exports = function typesafeMiddleware() {
return async (ctx, next) => {
try {
execSync('npm run type-check', { stdio: 'pipe' })
await next()
} catch (e) {
ctx.status = 500
ctx.body = { error: 'Type check failed', details: e.stdout.toString() }
}
}
}
// 开发环境启用类型检查
if (process.env.NODE_ENV === 'development') {
app.use(require('./ts-check')())
}
监控体系的架构集成
生产环境监控方案示例:
// core/monitor.js
const { NodeSDK } = require('@opentelemetry/sdk-node')
const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node')
module.exports = function initTelemetry() {
const sdk = new NodeSDK({
traceExporter: new ConsoleSpanExporter(),
instrumentations: [getNodeAutoInstrumentations()]
})
sdk.start()
process.on('SIGTERM', () => {
sdk.shutdown()
.then(() => console.log('Tracing terminated'))
.catch(err => console.error('Error terminating tracing', err))
})
}
// 在app.js最顶部引入
require('./core/monitor')()
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:领域驱动设计初步应用
下一篇:基准测试与性能分析工具