路由方法 #

一、HTTP方法概述 #

1.1 RESTful API设计 #

HTTP方法 CRUD操作 说明
GET Read 获取资源
POST Create 创建资源
PUT Update 完整更新资源
PATCH Update 部分更新资源
DELETE Delete 删除资源

1.2 Express支持的方法 #

javascript
app.get()
app.post()
app.put()
app.patch()
app.delete()
app.head()
app.options()
app.all()

二、GET方法 #

2.1 基本用法 #

GET方法用于获取资源:

javascript
app.get('/users', (req, res) => {
    res.json({ users: [] });
});

2.2 获取单个资源 #

javascript
app.get('/users/:id', (req, res) => {
    const { id } = req.params;
    res.json({ id, name: '用户名' });
});

2.3 带查询参数 #

javascript
app.get('/users', (req, res) => {
    const { page = 1, limit = 10, sort = 'desc' } = req.query;
    
    res.json({
        page: parseInt(page),
        limit: parseInt(limit),
        sort,
        users: []
    });
});

2.4 条件查询 #

javascript
app.get('/products', (req, res) => {
    const { category, minPrice, maxPrice, inStock } = req.query;
    
    const filters = {};
    
    if (category) filters.category = category;
    if (minPrice) filters.minPrice = parseFloat(minPrice);
    if (maxPrice) filters.maxPrice = parseFloat(maxPrice);
    if (inStock) filters.inStock = inStock === 'true';
    
    res.json({ filters, products: [] });
});

2.5 分页示例 #

javascript
const users = Array.from({ length: 100 }, (_, i) => ({
    id: i + 1,
    name: `用户${i + 1}`
}));

app.get('/users', (req, res) => {
    const page = parseInt(req.query.page) || 1;
    const limit = parseInt(req.query.limit) || 10;
    const skip = (page - 1) * limit;
    
    const paginatedUsers = users.slice(skip, skip + limit);
    
    res.json({
        page,
        limit,
        total: users.length,
        totalPages: Math.ceil(users.length / limit),
        data: paginatedUsers
    });
});

三、POST方法 #

3.1 基本用法 #

POST方法用于创建资源:

javascript
app.use(express.json());

app.post('/users', (req, res) => {
    const { name, email } = req.body;
    
    const newUser = {
        id: Date.now(),
        name,
        email,
        createdAt: new Date()
    };
    
    res.status(201).json(newUser);
});

3.2 表单数据处理 #

javascript
app.use(express.urlencoded({ extended: true }));

app.post('/login', (req, res) => {
    const { username, password } = req.body;
    
    if (username === 'admin' && password === '123456') {
        res.json({ success: true, message: '登录成功' });
    } else {
        res.status(401).json({ success: false, message: '用户名或密码错误' });
    }
});

3.3 文件上传 #

javascript
const multer = require('multer');
const upload = multer({ dest: 'uploads/' });

app.post('/upload', upload.single('file'), (req, res) => {
    res.json({
        message: '文件上传成功',
        file: req.file
    });
});

app.post('/photos', upload.array('photos', 5), (req, res) => {
    res.json({
        message: '多文件上传成功',
        files: req.files
    });
});

3.4 数据验证 #

javascript
app.post('/users', (req, res) => {
    const { name, email, password } = req.body;
    
    if (!name || !email || !password) {
        return res.status(400).json({ 
            error: '请填写所有必填字段' 
        });
    }
    
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    if (!emailRegex.test(email)) {
        return res.status(400).json({ 
            error: '请输入有效的邮箱地址' 
        });
    }
    
    if (password.length < 6) {
        return res.status(400).json({ 
            error: '密码至少6个字符' 
        });
    }
    
    res.status(201).json({ name, email });
});

四、PUT方法 #

4.1 基本用法 #

PUT方法用于完整更新资源:

javascript
app.put('/users/:id', (req, res) => {
    const { id } = req.params;
    const { name, email, age } = req.body;
    
    const updatedUser = {
        id: parseInt(id),
        name,
        email,
        age,
        updatedAt: new Date()
    };
    
    res.json(updatedUser);
});

4.2 完整替换 #

javascript
let users = [
    { id: 1, name: '张三', email: 'zhangsan@example.com' },
    { id: 2, name: '李四', email: 'lisi@example.com' }
];

app.put('/users/:id', (req, res) => {
    const { id } = req.params;
    const index = users.findIndex(u => u.id === parseInt(id));
    
    if (index === -1) {
        return res.status(404).json({ error: '用户不存在' });
    }
    
    users[index] = {
        id: parseInt(id),
        ...req.body,
        updatedAt: new Date()
    };
    
    res.json(users[index]);
});

五、PATCH方法 #

5.1 基本用法 #

PATCH方法用于部分更新资源:

javascript
app.patch('/users/:id', (req, res) => {
    const { id } = req.params;
    const updates = req.body;
    
    res.json({
        id: parseInt(id),
        ...updates,
        updatedAt: new Date()
    });
});

5.2 部分更新示例 #

javascript
let users = [
    { id: 1, name: '张三', email: 'zhangsan@example.com', age: 25 },
    { id: 2, name: '李四', email: 'lisi@example.com', age: 30 }
];

app.patch('/users/:id', (req, res) => {
    const { id } = req.params;
    const index = users.findIndex(u => u.id === parseInt(id));
    
    if (index === -1) {
        return res.status(404).json({ error: '用户不存在' });
    }
    
    const allowedUpdates = ['name', 'email', 'age'];
    const updates = Object.keys(req.body);
    const isValid = updates.every(update => allowedUpdates.includes(update));
    
    if (!isValid) {
        return res.status(400).json({ error: '无效的更新字段' });
    }
    
    users[index] = {
        ...users[index],
        ...req.body,
        updatedAt: new Date()
    };
    
    res.json(users[index]);
});

六、DELETE方法 #

6.1 基本用法 #

DELETE方法用于删除资源:

javascript
app.delete('/users/:id', (req, res) => {
    const { id } = req.params;
    res.status(204).send();
});

6.2 返回被删除的资源 #

javascript
let users = [
    { id: 1, name: '张三' },
    { id: 2, name: '李四' }
];

app.delete('/users/:id', (req, res) => {
    const { id } = req.params;
    const index = users.findIndex(u => u.id === parseInt(id));
    
    if (index === -1) {
        return res.status(404).json({ error: '用户不存在' });
    }
    
    const deletedUser = users.splice(index, 1)[0];
    res.json({ 
        message: '删除成功',
        user: deletedUser 
    });
});

6.3 批量删除 #

javascript
app.delete('/users', (req, res) => {
    const { ids } = req.body;
    
    if (!Array.isArray(ids)) {
        return res.status(400).json({ error: 'ids必须是数组' });
    }
    
    res.json({ 
        message: '批量删除成功',
        count: ids.length 
    });
});

七、HEAD方法 #

7.1 基本用法 #

HEAD方法只返回响应头,不返回响应体:

javascript
app.head('/users', (req, res) => {
    res.set('X-Total-Count', '100');
    res.end();
});

7.2 检查资源是否存在 #

javascript
app.head('/files/:filename', (req, res) => {
    const { filename } = req.params;
    
    if (fileExists(filename)) {
        res.set('Content-Type', 'application/pdf');
        res.set('Content-Length', getFileSize(filename));
        res.status(200).end();
    } else {
        res.status(404).end();
    }
});

八、OPTIONS方法 #

8.1 基本用法 #

OPTIONS方法返回服务器支持的方法:

javascript
app.options('/users', (req, res) => {
    res.set('Allow', 'GET, POST, PUT, DELETE');
    res.end();
});

8.2 CORS预检请求 #

javascript
app.options('/api/*', (req, res) => {
    res.set({
        'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, PATCH',
        'Access-Control-Allow-Headers': 'Content-Type, Authorization',
        'Access-Control-Max-Age': '86400'
    });
    res.end();
});

九、app.all() #

9.1 匹配所有方法 #

javascript
app.all('/api/*', (req, res, next) => {
    console.log(`${req.method} ${req.path}`);
    next();
});

9.2 认证保护 #

javascript
app.all('/admin/*', (req, res, next) => {
    if (!req.user || req.user.role !== 'admin') {
        return res.status(403).json({ error: '需要管理员权限' });
    }
    next();
});

9.3 日志记录 #

javascript
app.all('*', (req, res, next) => {
    console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
    next();
});

十、app.route() #

10.1 链式路由 #

javascript
app.route('/articles')
    .get((req, res) => {
        res.json({ articles: [] });
    })
    .post((req, res) => {
        res.status(201).json(req.body);
    });

app.route('/articles/:id')
    .get((req, res) => {
        res.json({ id: req.params.id });
    })
    .put((req, res) => {
        res.json({ id: req.params.id, ...req.body });
    })
    .delete((req, res) => {
        res.status(204).send();
    });

10.2 完整CRUD示例 #

javascript
let articles = [];

app.route('/articles')
    .get((req, res) => {
        res.json(articles);
    })
    .post((req, res) => {
        const article = {
            id: articles.length + 1,
            ...req.body,
            createdAt: new Date()
        };
        articles.push(article);
        res.status(201).json(article);
    });

app.route('/articles/:id')
    .get((req, res) => {
        const article = articles.find(a => a.id === parseInt(req.params.id));
        if (!article) {
            return res.status(404).json({ error: '文章不存在' });
        }
        res.json(article);
    })
    .put((req, res) => {
        const index = articles.findIndex(a => a.id === parseInt(req.params.id));
        if (index === -1) {
            return res.status(404).json({ error: '文章不存在' });
        }
        articles[index] = {
            ...articles[index],
            ...req.body,
            updatedAt: new Date()
        };
        res.json(articles[index]);
    })
    .delete((req, res) => {
        const index = articles.findIndex(a => a.id === parseInt(req.params.id));
        if (index === -1) {
            return res.status(404).json({ error: '文章不存在' });
        }
        articles.splice(index, 1);
        res.status(204).send();
    });

十一、RESTful最佳实践 #

11.1 资源命名 #

好的设计 不好的设计
GET /users GET /getUsers
POST /users POST /createUser
PUT /users/:id PUT /updateUser/:id
DELETE /users/:id DELETE /deleteUser/:id

11.2 状态码使用 #

状态码 说明 使用场景
200 成功 GET、PUT、PATCH
201 创建成功 POST
204 无内容 DELETE
400 错误请求 参数验证失败
401 未认证 需要登录
403 禁止访问 无权限
404 未找到 资源不存在
500 服务器错误 程序错误

11.3 响应格式 #

成功响应:

javascript
res.json({
    success: true,
    data: { },
    message: '操作成功'
});

错误响应:

javascript
res.status(400).json({
    success: false,
    error: '错误信息',
    code: 'ERROR_CODE'
});

十二、总结 #

路由方法要点:

方法 用途 幂等性
GET 获取资源
POST 创建资源
PUT 完整更新
PATCH 部分更新
DELETE 删除资源

下一步,让我们学习路由参数!

最后更新:2026-03-28