Custom middleware encapsulation and publishing
Basic Concepts of Middleware
Koa2 middleware is essentially a function that takes the context object and the next function as parameters. Middleware controls the execution flow through the next function, forming an onion model. Each middleware can process requests and responses, modify the context object, or terminate the request.
async function middleware(ctx, next) {
// Request processing logic
await next()
// Response processing logic
}
Principles of Middleware Encapsulation
When encapsulating middleware, the Single Responsibility Principle should be considered, where each middleware handles only a specific functionality. Good middleware should be configurable, allowing custom behavior through an options parameter. Error handling mechanisms are essential, and internal errors should be caught and thrown via ctx.throw
.
function createMiddleware(options = {}) {
return async function(ctx, next) {
try {
// Middleware logic
await next()
} catch(err) {
ctx.throw(500, 'Internal Server Error')
}
}
}
Common Middleware Encapsulation Patterns
Configurable Middleware
Return a middleware instance through a factory function, supporting parameter configuration. For example, a logging middleware can configure the log level:
function logger(options = { level: 'info' }) {
return async (ctx, next) => {
const start = Date.now()
await next()
const ms = Date.now() - start
if(options.level === 'debug') {
console.debug(`${ctx.method} ${ctx.url} - ${ms}ms`)
} else {
console.log(`${ctx.method} ${ctx.url}`)
}
}
}
Composite Middleware
Combine multiple functionalities into a composite middleware, such as integrating authentication and authorization:
function auth(options) {
const authenticate = require('./authenticate')
const authorize = require('./authorize')
return async (ctx, next) => {
await authenticate(options)(ctx, async () => {
await authorize(options)(ctx, next)
})
}
}
Middleware Development Practices
Example of Request Processing Middleware
Developing a request parameter validation middleware:
function validate(schema) {
return async (ctx, next) => {
const { error } = schema.validate(ctx.request.body)
if (error) {
ctx.status = 400
ctx.body = { error: error.details[0].message }
return
}
await next()
}
}
// Usage example
const Joi = require('joi')
const userSchema = Joi.object({
username: Joi.string().required(),
password: Joi.string().min(6).required()
})
app.use(validate(userSchema))
Example of Response Processing Middleware
A unified response formatting middleware:
function responseFormatter() {
return async (ctx, next) => {
await next()
if (!ctx.body) return
ctx.body = {
code: ctx.status,
data: ctx.body,
timestamp: Date.now()
}
}
}
Middleware Testing Methods
Testing middleware using supertest and jest:
const request = require('supertest')
const Koa = require('koa')
const app = new Koa()
app.use(require('./middleware'))
test('should return 400 for invalid input', async () => {
const response = await request(app.callback())
.post('/api')
.send({})
expect(response.status).toBe(400)
})
Middleware Publishing Process
Package Structure Standards
Typical npm package directory structure for middleware:
/package-name
/lib
- index.js
/test
- middleware.test.js
- package.json
- README.md
package.json Configuration
Key fields configuration example:
{
"name": "koa-validate",
"version": "1.0.0",
"main": "lib/index.js",
"keywords": ["koa", "middleware", "validation"],
"peerDependencies": {
"koa": "^2.0.0"
}
}
Documentation Writing Essentials
README.md should include:
- Installation instructions
- Basic usage examples
- Configuration options explanation
- Frequently asked questions
# koa-validate
## Installation
```bash
npm install koa-validate
Basic Usage
app.use(validate(schema))
## Version Management and Updates
Follow semantic versioning:
- Patch version (1.0.x): Backward-compatible bug fixes
- Minor version (1.x.0): Backward-compatible feature additions
- Major version (x.0.0): Incompatible API changes
Use npm version commands to manage versions:
```bash
npm version patch
npm version minor
npm version major
Performance Optimization Tips
Avoid blocking operations in middleware. For time-consuming operations, use asynchronous methods:
function cacheMiddleware(ttl) {
const cache = new Map()
return async (ctx, next) => {
const key = ctx.url
if (cache.has(key)) {
const { value, expiry } = cache.get(key)
if (Date.now() < expiry) {
ctx.body = value
return
}
}
await next()
if (ctx.status === 200) {
cache.set(key, {
value: ctx.body,
expiry: Date.now() + ttl
})
}
}
}
Error Handling Best Practices
Internal middleware errors should trigger application-level error events via ctx.app.emit
:
function errorHandler() {
return async (ctx, next) => {
try {
await next()
} catch (err) {
ctx.status = err.status || 500
ctx.body = { message: err.message }
ctx.app.emit('error', err, ctx)
}
}
}
Middleware Composition Techniques
Use koa-compose to combine multiple middleware:
const compose = require('koa-compose')
function middlewareA() { /* ... */ }
function middlewareB() { /* ... */ }
const combined = compose([middlewareA(), middlewareB()])
app.use(combined)
TypeScript Support
Add type declarations for middleware:
import { Middleware } from 'koa'
interface Options {
prefix?: string
}
export function myMiddleware(options?: Options): Middleware {
return async (ctx, next) => {
// Implementation logic
await next()
}
}
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:中间件的单元测试方法
下一篇:中间件组合与复用技巧