您现在的位置是:网站首页 > 请求与响应对象详解文章详情
请求与响应对象详解
陈川
【
Node.js
】
10775人已围观
6385字
请求对象详解
Express框架中的请求对象(req)封装了HTTP请求的详细信息。这个对象提供了访问客户端请求数据的接口,包含请求头、参数、正文等信息。
基本属性
请求对象包含多个常用属性:
req.method
: 获取HTTP请求方法(GET、POST等)req.url
: 获取请求的URL路径req.headers
: 获取请求头对象req.protocol
: 获取协议类型(http或https)
app.get('/user', (req, res) => {
console.log(req.method); // "GET"
console.log(req.url); // "/user"
console.log(req.headers['user-agent']);
});
查询参数处理
Express自动解析URL中的查询字符串,可通过req.query
访问:
// 请求 /search?q=express&page=2
app.get('/search', (req, res) => {
console.log(req.query.q); // "express"
console.log(req.query.page); // "2"
});
路由参数获取
使用冒号定义的路由参数可通过req.params
访问:
app.get('/users/:userId/posts/:postId', (req, res) => {
console.log(req.params.userId); // 用户ID
console.log(req.params.postId); // 帖子ID
});
请求体解析
处理POST请求时需要中间件解析请求体:
const express = require('express');
const bodyParser = require('body-parser');
app.use(bodyParser.json()); // 解析JSON格式
app.use(bodyParser.urlencoded({ extended: true })); // 解析表单数据
app.post('/submit', (req, res) => {
console.log(req.body.username); // 表单字段
console.log(req.body.password);
});
文件上传处理
使用multer中间件处理文件上传:
const multer = require('multer');
const upload = multer({ dest: 'uploads/' });
app.post('/upload', upload.single('avatar'), (req, res) => {
console.log(req.file); // 上传文件信息
console.log(req.body); // 其他表单字段
});
响应对象详解
响应对象(res)用于向客户端发送HTTP响应,控制响应的状态码、头信息和内容。
基本响应方法
最常用的响应方法包括:
res.send()
: 发送各种类型响应res.json()
: 发送JSON响应res.status()
: 设置HTTP状态码
app.get('/api/data', (req, res) => {
res.status(200).json({
success: true,
data: { id: 1, name: 'Example' }
});
});
设置响应头
使用res.set()
方法设置自定义响应头:
app.get('/download', (req, res) => {
res.set('Content-Type', 'application/pdf');
res.set('Content-Disposition', 'attachment; filename="report.pdf"');
// 发送文件内容...
});
重定向处理
实现页面重定向的几种方式:
// 基本重定向
app.get('/old', (req, res) => {
res.redirect('/new');
});
// 带状态码的重定向
app.get('/temp', (req, res) => {
res.redirect(302, '/new-location');
});
文件下载
发送文件作为响应:
const path = require('path');
app.get('/download-report', (req, res) => {
const filePath = path.join(__dirname, 'reports', 'annual.pdf');
res.download(filePath, 'annual-report-2023.pdf', (err) => {
if (err) {
// 处理错误
}
});
});
流式响应
处理大文件时使用流:
const fs = require('fs');
app.get('/video', (req, res) => {
const videoPath = 'assets/sample.mp4';
const stat = fs.statSync(videoPath);
const fileSize = stat.size;
const range = req.headers.range;
if (range) {
// 处理部分内容请求(用于视频流)
const parts = range.replace(/bytes=/, "").split("-");
const start = parseInt(parts[0], 10);
const end = parts[1] ? parseInt(parts[1], 10) : fileSize-1;
res.writeHead(206, {
'Content-Range': `bytes ${start}-${end}/${fileSize}`,
'Accept-Ranges': 'bytes',
'Content-Length': end-start+1,
'Content-Type': 'video/mp4'
});
fs.createReadStream(videoPath, {start, end}).pipe(res);
} else {
res.writeHead(200, {
'Content-Length': fileSize,
'Content-Type': 'video/mp4'
});
fs.createReadStream(videoPath).pipe(res);
}
});
请求与响应对象的高级用法
自定义中间件处理
创建处理请求和响应的中间件:
// 记录请求时间的中间件
app.use((req, res, next) => {
req.requestTime = Date.now();
const originalSend = res.send;
res.send = function(body) {
console.log(`请求处理时间: ${Date.now() - req.requestTime}ms`);
originalSend.call(this, body);
};
next();
});
内容协商
根据Accept头返回不同格式的响应:
app.get('/resource', (req, res) => {
const accepts = req.accepts(['json', 'html', 'xml']);
switch(accepts) {
case 'json':
res.json({ data: 'value' });
break;
case 'xml':
res.type('application/xml');
res.send('<data>value</data>');
break;
default:
res.send('<p>value</p>');
}
});
错误处理中间件
集中处理请求过程中的错误:
app.get('/error-prone', (req, res, next) => {
try {
// 可能出错的代码
throw new Error('示例错误');
} catch(err) {
next(err); // 传递给错误处理中间件
}
});
// 错误处理中间件
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({
error: err.message,
stack: process.env.NODE_ENV === 'development' ? err.stack : undefined
});
});
性能优化技巧
响应压缩
使用compression中间件减小响应体积:
const compression = require('compression');
// 在所有路由前使用
app.use(compression({
level: 6, // 压缩级别
threshold: 1024, // 大于1KB才压缩
filter: (req, res) => {
if (req.headers['x-no-compression']) {
return false;
}
return compression.filter(req, res);
}
}));
缓存控制
设置适当的缓存头:
app.get('/static-data', (req, res) => {
res.set('Cache-Control', 'public, max-age=3600'); // 缓存1小时
res.json(getCachedData());
});
流式处理大响应
避免内存中构建大响应:
app.get('/large-data', (req, res) => {
const dataStream = getLargeDataStream(); // 返回可读流
res.type('application/json');
res.write('['); // 开始JSON数组
let first = true;
dataStream.on('data', (chunk) => {
if (!first) res.write(',');
first = false;
res.write(JSON.stringify(chunk));
});
dataStream.on('end', () => {
res.end(']'); // 结束JSON数组
});
});
安全相关实践
CSRF防护
使用csurf中间件:
const csrf = require('csurf');
const csrfProtection = csrf({ cookie: true });
// 在表单页面生成token
app.get('/form', csrfProtection, (req, res) => {
res.render('form', { csrfToken: req.csrfToken() });
});
// 验证提交的token
app.post('/process', csrfProtection, (req, res) => {
// 如果token验证通过才会执行到这里
res.send('表单处理成功');
});
安全头部设置
使用helmet中间件增强安全性:
const helmet = require('helmet');
app.use(helmet());
app.use(helmet.contentSecurityPolicy({
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "'unsafe-inline'", 'cdn.example.com'],
styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", 'data:', 'cdn.example.com']
}
}));
速率限制
防止暴力破解攻击:
const rateLimit = require('express-rate-limit');
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15分钟
max: 100, // 每个IP最多100次请求
message: '请求过于频繁,请稍后再试'
});
app.use('/api/', limiter);
上一篇: 中间件机制与执行流程
下一篇: 设计模式的定义与重要性