Skip to content
On this page

Express中间件

中间件函数是Express框架的核心概念,它能够访问请求对象(req)、响应对象(res)和next函数。中间件函数可以执行以下任务:

  • 执行任何代码
  • 修改请求和响应对象
  • 结束请求-响应循环
  • 调用栈中的下一个中间件函数

中间件类型

应用级中间件

应用级中间件绑定到应用实例使用app.use()或app.METHOD()函数。

javascript
const express = require('express');
const app = express();

// 普通中间件
app.use((req, res, next) => {
  console.log('Time:', Date.now());
  next();
});

// 路径特定中间件
app.use('/user/:id', (req, res, next) => {
  console.log('Request Type:', req.method);
  next();
});

// 路由中间件
app.get('/user/:id', (req, res, next) => {
  console.log('Request URL:', req.originalUrl);
  next();
}, (req, res) => {
  res.send('User Info');
});

路由级中间件

路由级中间件与应用级中间件类似,但使用的是express.Router()实例。

javascript
const express = require('express');
const app = express();
const router = express.Router();

// 路由级中间件
router.use((req, res, next) => {
  console.log('Time:', Date.now());
  next();
});

router.get('/', (req, res) => {
  res.send('Router homepage');
});

app.use('/router', router);

错误处理中间件

错误处理中间件有四个参数,必须有四个参数Express才会将其识别为错误处理中间件。

javascript
app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).send('Something broke!');
});

内置中间件

Express唯一的内置中间件是express.static(),用于提供静态文件。

javascript
app.use(express.static('public'));
app.use('/static', express.static('public')); // 自定义虚拟路径

第三方中间件

通过npm安装第三方中间件来扩展功能。

javascript
const cookieParser = require('cookie-parser');
const session = require('express-session');

app.use(cookieParser());
app.use(session());

中间件函数编写

基本中间件结构

javascript
const myMiddleware = (req, res, next) => {
  // 执行中间件逻辑
  console.log('Middleware executed');
  
  // 调用next()继续执行下一个中间件
  next();
};

app.use(myMiddleware);

条件中间件

javascript
const conditionalMiddleware = (req, res, next) => {
  if (req.headers.authorization) {
    next(); // 如果有授权头,继续
  } else {
    res.status(401).send('Unauthorized');
  }
};

app.use('/api', conditionalMiddleware);

参数化中间件

javascript
const createMiddleware = (options) => {
  return (req, res, next) => {
    console.log(`Option value: ${options.value}`);
    next();
  };
};

app.use(createMiddleware({ value: 'example' }));

常用内置中间件

body解析中间件

javascript
// 解析JSON请求体
app.use(express.json());

// 解析URL编码的请求体
app.use(express.urlencoded({ extended: true }));

// 解析文本请求体
app.use(express.text());

// 解析原始请求体
app.use(express.raw());

配置选项

javascript
// JSON解析配置
app.use(express.json({
  type: 'application/json',
  limit: '10mb', // 限制请求体大小
  strict: true   // 严格模式,只解析数组和对象
}));

// URL编码配置
app.use(express.urlencoded({
  extended: false, // 使用querystring库
  limit: '10mb'
}));

第三方中间件

CORS中间件

javascript
const cors = require('cors');

// 启用所有CORS请求
app.use(cors());

// 配置CORS
app.use(cors({
  origin: ['http://localhost:3000', 'https://example.com'],
  credentials: true
}));

日志中间件

javascript
const morgan = require('morgan');

// 使用预定义格式
app.use(morgan('combined'));

// 自定义格式
app.use(morgan(':method :url :status :res[content-length] - :response-time ms'));

安全中间件

javascript
const helmet = require('helmet');

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

// 配置特定安全头
app.use(helmet({
  contentSecurityPolicy: {
    directives: {
      defaultSrc: ["'self'"],
      styleSrc: ["'self'", "'unsafe-inline'"]
    }
  }
}));

中间件执行顺序

中间件按照定义的顺序执行:

javascript
app.use((req, res, next) => {
  console.log('Middleware 1');
  next();
});

app.use((req, res, next) => {
  console.log('Middleware 2');
  next();
});

app.get('/', (req, res) => {
  res.send('Hello World');
});

// 输出:
// Middleware 1
// Middleware 2

路径特定中间件

javascript
// 只在/api路径下执行
app.use('/api', (req, res, next) => {
  console.log('API middleware');
  next();
});

// 多个路径
app.use(['/api', '/admin'], (req, res, next) => {
  console.log('API or Admin middleware');
  next();
});

中间件最佳实践

1. 错误处理

javascript
// 正确的错误处理中间件
app.use((err, req, res, next) => {
  console.error(err.stack);
  
  if (process.env.NODE_ENV === 'production') {
    res.status(500).json({ error: 'Internal Server Error' });
  } else {
    res.status(500).json({ error: err.message });
  }
});

2. 异步错误处理

javascript
// 处理异步错误
const asyncHandler = (fn) => (req, res, next) => {
  Promise.resolve(fn(req, res, next)).catch(next);
};

app.get('/async', asyncHandler(async (req, res) => {
  const data = await someAsyncOperation();
  res.json(data);
}));

3. 中间件复用

javascript
// 认证中间件
const authenticate = (req, res, next) => {
  const token = req.headers.authorization?.split(' ')[1];
  
  if (!token) {
    return res.status(401).json({ error: 'No token provided' });
  }
  
  // 验证token
  try {
    const decoded = jwt.verify(token, process.env.JWT_SECRET);
    req.user = decoded;
    next();
  } catch (err) {
    res.status(401).json({ error: 'Invalid token' });
  }
};

// 在需要认证的路由中使用
app.get('/profile', authenticate, (req, res) => {
  res.json(req.user);
});

4. 中间件配置

javascript
// 可配置的中间件
const rateLimit = require('express-rate-limit');

const limiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15分钟
  max: 100 // 限制每个IP 15分钟内最多100个请求
});

app.use(limiter);

中间件模式

中间件链

javascript
const middleware1 = (req, res, next) => {
  req.timestamp = Date.now();
  next();
};

const middleware2 = (req, res, next) => {
  req.processed = true;
  next();
};

app.get('/example', [middleware1, middleware2], (req, res) => {
  res.json({
    timestamp: req.timestamp,
    processed: req.processed
  });
});

条件中间件应用

javascript
// 仅在开发环境使用日志
if (process.env.NODE_ENV === 'development') {
  app.use(morgan('dev'));
}

// 根据路径条件应用中间件
app.use((req, res, next) => {
  if (req.path.startsWith('/api/')) {
    // API特定中间件
    req.isApiRequest = true;
  }
  next();
});

中间件性能考虑

1. 避免不必要的中间件

javascript
// 避免在所有路由上应用不必要的中间件
app.use('/api', expensiveMiddleware); // 只在需要的地方应用

2. 中间件缓存

javascript
// 使用缓存避免重复计算
const memoryCache = require('memory-cache');

const cachedMiddleware = (req, res, next) => {
  const key = '__middleware__' + req.originalUrl || req.url;
  const cachedBody = memoryCache.get(key);
  
  if (cachedBody) {
    res.send(cachedBody);
  } else {
    res.sendResponse = res.send;
    res.send = (body) => {
      memoryCache.put(key, body, 1000 * 10); // 缓存10秒
      res.sendResponse(body);
    };
    next();
  }
};

Express中间件是构建可扩展和可维护应用的关键。通过合理使用中间件,可以将应用逻辑分解为可重用的组件,提高代码的组织性和可维护性。