RESTful API开发支持
RESTful API是一种基于HTTP协议的API设计风格,它通过URL定位资源,利用HTTP方法(GET、POST、PUT、DELETE等)描述操作,使得接口设计更加清晰和规范。Express作为Node.js的轻量级框架,提供了强大的工具和中间件支持,非常适合用于构建RESTful API。
RESTful API的核心原则
RESTful API的设计遵循几个核心原则:
- 资源导向:每个URL代表一种资源,资源是名词而非动词。例如,
/users
表示用户资源,而不是/getUsers
这样的动作。 - HTTP方法明确操作:
- GET:获取资源
- POST:创建资源
- PUT:更新资源
- DELETE:删除资源
- 无状态性:每次请求必须包含所有必要信息,服务器不保存客户端状态。
- 返回标准化数据:通常使用JSON格式返回数据。
Express中实现RESTful API
Express通过路由和中间件机制,可以轻松实现RESTful API。以下是一个基础的Express应用结构:
const express = require('express');
const app = express();
const port = 3000;
// 中间件:解析JSON请求体
app.use(express.json());
// 模拟数据库
let users = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' }
];
// GET /users - 获取所有用户
app.get('/users', (req, res) => {
res.json(users);
});
// POST /users - 创建新用户
app.post('/users', (req, res) => {
const newUser = req.body;
users.push(newUser);
res.status(201).json(newUser);
});
// 启动服务器
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});
资源嵌套与路由设计
对于复杂资源关系,可以采用嵌套路由设计。例如,用户可能有多个帖子:
// 用户帖子数据
let posts = {
1: [
{ id: 101, title: 'Post 1' },
{ id: 102, title: 'Post 2' }
],
2: [
{ id: 201, title: 'Post 3' }
]
};
// GET /users/:userId/posts - 获取特定用户的所有帖子
app.get('/users/:userId/posts', (req, res) => {
const userPosts = posts[req.params.userId] || [];
res.json(userPosts);
});
// POST /users/:userId/posts - 为特定用户创建新帖子
app.post('/users/:userId/posts', (req, res) => {
const userId = req.params.userId;
const newPost = req.body;
if (!posts[userId]) {
posts[userId] = [];
}
posts[userId].push(newPost);
res.status(201).json(newPost);
});
错误处理与状态码
正确的HTTP状态码对于API设计至关重要。Express中可以这样处理错误:
// GET /users/:id - 获取单个用户
app.get('/users/:id', (req, res) => {
const user = users.find(u => u.id === parseInt(req.params.id));
if (!user) {
return res.status(404).json({ error: 'User not found' });
}
res.json(user);
});
// 全局错误处理中间件
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ error: 'Something went wrong!' });
});
版本控制
随着API演进,版本控制变得重要。常见做法是在URL中包含版本号:
// v1路由
app.get('/api/v1/users', (req, res) => {
res.json({ version: 'v1', users });
});
// v2路由
app.get('/api/v2/users', (req, res) => {
res.json({
version: 'v2',
users: users.map(u => ({ ...u, timestamp: new Date() }))
});
});
认证与授权
保护API通常需要认证机制。以下是使用JWT的简单示例:
const jwt = require('jsonwebtoken');
const SECRET = 'your-secret-key';
// 登录路由
app.post('/login', (req, res) => {
const { username, password } = req.body;
// 验证逻辑(简化)
if (username === 'admin' && password === '123456') {
const token = jwt.sign({ username }, SECRET, { expiresIn: '1h' });
return res.json({ token });
}
res.status(401).json({ error: 'Invalid credentials' });
});
// 需要认证的路由
app.get('/protected', (req, res) => {
const token = req.headers['authorization'];
if (!token) {
return res.status(403).json({ error: 'No token provided' });
}
try {
const decoded = jwt.verify(token, SECRET);
res.json({ message: `Hello ${decoded.username}`, secretData: '42' });
} catch (err) {
res.status(401).json({ error: 'Invalid token' });
}
});
性能优化
对于数据量大的响应,可以考虑分页:
// 模拟大量数据
const bigData = Array.from({ length: 1000 }, (_, i) => ({ id: i, value: Math.random() }));
// 带分页的API
app.get('/data', (req, res) => {
const page = parseInt(req.query.page) || 1;
const limit = parseInt(req.query.limit) || 10;
const startIndex = (page - 1) * limit;
const endIndex = page * limit;
const results = {
data: bigData.slice(startIndex, endIndex),
total: bigData.length,
page,
totalPages: Math.ceil(bigData.length / limit)
};
res.json(results);
});
文档化API
良好的文档对API使用者至关重要。可以使用Swagger等工具:
const swaggerJsdoc = require('swagger-jsdoc');
const swaggerUi = require('swagger-ui-express');
const options = {
definition: {
openapi: '3.0.0',
info: {
title: 'Users API',
version: '1.0.0',
},
},
apis: ['./routes/*.js'], // 包含注释的文件
};
const specs = swaggerJsdoc(options);
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(specs));
在路由文件中添加JSDoc注释:
/**
* @swagger
* /users:
* get:
* summary: 获取所有用户
* responses:
* 200:
* description: 用户列表
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: '#/components/schemas/User'
*/
app.get('/users', (req, res) => {
// 实现代码
});
测试API
自动化测试对保证API质量很重要。使用Jest和Supertest的测试示例:
const request = require('supertest');
const app = require('../app');
describe('Users API', () => {
it('GET /users - 获取所有用户', async () => {
const response = await request(app).get('/users');
expect(response.statusCode).toBe(200);
expect(response.body).toBeInstanceOf(Array);
});
it('POST /users - 创建新用户', async () => {
const newUser = { name: 'Charlie' };
const response = await request(app)
.post('/users')
.send(newUser);
expect(response.statusCode).toBe(201);
expect(response.body).toHaveProperty('id');
expect(response.body.name).toBe(newUser.name);
});
});
部署考虑
部署RESTful API时需要考虑:
- 环境变量管理(使用dotenv)
- 进程管理(使用PM2)
- 反向代理(Nginx配置)
- HTTPS启用
- CORS配置
// CORS配置示例
const cors = require('cors');
app.use(cors({
origin: ['https://example.com', 'https://api.example.com'],
methods: ['GET', 'POST', 'PUT', 'DELETE']
}));
// HTTPS重定向中间件
app.use((req, res, next) => {
if (req.headers['x-forwarded-proto'] !== 'https') {
return res.redirect(301, `https://${req.headers.host}${req.url}`);
}
next();
});
监控与日志
生产环境需要完善的监控和日志系统:
const morgan = require('morgan');
const fs = require('fs');
const path = require('path');
// 访问日志
const accessLogStream = fs.createWriteStream(
path.join(__dirname, 'access.log'),
{ flags: 'a' }
);
app.use(morgan('combined', { stream: accessLogStream }));
// 健康检查端点
app.get('/health', (req, res) => {
res.json({
status: 'UP',
timestamp: new Date(),
uptime: process.uptime()
});
});
缓存策略
合理使用缓存提高性能:
const apicache = require('apicache');
let cache = apicache.middleware;
// 缓存所有GET请求5分钟
app.use(cache('5 minutes'));
// 特定路由缓存
app.get('/heavy-endpoint', cache('10 minutes'), (req, res) => {
// 耗时操作
res.json({ result: 'complex data' });
});
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:文件上传与下载处理
下一篇:WebSocket集成方案