Response对象 #
一、Response对象概述 #
1.1 什么是Response对象? #
Response对象(通常简写为res)代表了HTTP响应。通过它可以向客户端发送响应数据、设置响应头、状态码等。
1.2 基本结构 #
javascript
app.get('/', (req, res) => {
res.status(200);
res.set('Content-Type', 'application/json');
res.json({ message: 'Hello' });
});
二、响应方法 #
2.1 res.send() #
发送各种类型的响应:
javascript
app.get('/text', (req, res) => {
res.send('文本响应');
});
app.get('/html', (req, res) => {
res.send('<h1>HTML响应</h1>');
});
app.get('/json', (req, res) => {
res.send({ message: 'JSON响应' });
});
app.get('/buffer', (req, res) => {
res.send(Buffer.from('Buffer响应'));
});
2.2 res.json() #
发送JSON响应:
javascript
app.get('/api/users', (req, res) => {
res.json({
success: true,
data: [
{ id: 1, name: '张三' },
{ id: 2, name: '李四' }
]
});
});
app.get('/error', (req, res) => {
res.status(400).json({
success: false,
error: '请求参数错误'
});
});
2.3 res.status() #
设置HTTP状态码:
javascript
app.get('/ok', (req, res) => {
res.status(200).send('成功');
});
app.get('/created', (req, res) => {
res.status(201).json({ message: '资源创建成功' });
});
app.get('/no-content', (req, res) => {
res.status(204).send();
});
app.get('/bad-request', (req, res) => {
res.status(400).json({ error: '错误的请求' });
});
app.get('/unauthorized', (req, res) => {
res.status(401).json({ error: '未授权' });
});
app.get('/forbidden', (req, res) => {
res.status(403).json({ error: '禁止访问' });
});
app.get('/not-found', (req, res) => {
res.status(404).json({ error: '资源未找到' });
});
app.get('/error', (req, res) => {
res.status(500).json({ error: '服务器错误' });
});
2.4 res.redirect() #
重定向:
javascript
app.get('/old', (req, res) => {
res.redirect('/new');
});
app.get('/new', (req, res) => {
res.send('新页面');
});
app.get('/external', (req, res) => {
res.redirect('https://expressjs.com');
});
app.get('/permanent', (req, res) => {
res.redirect(301, '/new-location');
});
app.get('/temporary', (req, res) => {
res.redirect(302, '/temporary-location');
});
2.5 res.render() #
渲染模板:
javascript
app.set('view engine', 'ejs');
app.get('/', (req, res) => {
res.render('index', {
title: '首页',
message: '欢迎来到Express'
});
});
app.get('/user/:id', (req, res) => {
res.render('user', {
userId: req.params.id,
user: { name: '张三', email: 'zhangsan@example.com' }
});
});
2.6 res.sendFile() #
发送文件:
javascript
const path = require('path');
app.get('/download', (req, res) => {
const filePath = path.join(__dirname, 'files', 'document.pdf');
res.sendFile(filePath);
});
app.get('/download-with-options', (req, res) => {
const filePath = path.join(__dirname, 'files', 'document.pdf');
res.sendFile(filePath, {
root: __dirname,
dotfiles: 'deny',
headers: {
'x-timestamp': Date.now(),
'x-sent': true
}
});
});
2.7 res.download() #
触发浏览器下载:
javascript
app.get('/download-file', (req, res) => {
const filePath = path.join(__dirname, 'files', 'report.pdf');
res.download(filePath);
});
app.get('/download-custom-name', (req, res) => {
const filePath = path.join(__dirname, 'files', 'report.pdf');
res.download(filePath, '月度报告.pdf');
});
app.get('/download-callback', (req, res) => {
const filePath = path.join(__dirname, 'files', 'report.pdf');
res.download(filePath, (err) => {
if (err) {
console.error('下载失败:', err);
} else {
console.log('下载成功');
}
});
});
2.8 res.end() #
结束响应:
javascript
app.get('/end', (req, res) => {
res.end();
});
app.get('/end-data', (req, res) => {
res.end('响应结束');
});
三、响应头 #
3.1 res.set() / res.header() #
设置响应头:
javascript
app.get('/headers', (req, res) => {
res.set('Content-Type', 'application/json');
res.set('X-Custom-Header', 'value');
res.json({ message: 'Headers set' });
});
app.get('/multiple-headers', (req, res) => {
res.set({
'Content-Type': 'application/json',
'Cache-Control': 'no-cache',
'X-Powered-By': 'Express'
});
res.json({ message: 'Multiple headers set' });
});
3.2 res.get() #
获取已设置的响应头:
javascript
app.get('/get-header', (req, res) => {
res.set('Content-Type', 'application/json');
const contentType = res.get('Content-Type');
res.json({ contentType });
});
3.3 res.append() #
追加响应头:
javascript
app.get('/append-header', (req, res) => {
res.append('Set-Cookie', 'name=express');
res.append('Set-Cookie', 'lang=zh');
res.send('Cookies set');
});
3.4 res.removeHeader() #
删除响应头:
javascript
app.get('/remove-header', (req, res) => {
res.removeHeader('X-Powered-By');
res.send('Header removed');
});
四、Cookie操作 #
4.1 res.cookie() #
设置Cookie:
javascript
app.get('/set-cookie', (req, res) => {
res.cookie('name', 'express');
res.send('Cookie已设置');
});
app.get('/set-cookie-options', (req, res) => {
res.cookie('token', 'abc123', {
maxAge: 900000,
httpOnly: true,
secure: true,
sameSite: 'strict',
domain: 'example.com',
path: '/admin',
signed: true
});
res.send('Cookie已设置');
});
Cookie选项:
| 选项 | 说明 |
|---|---|
| maxAge | 过期时间(毫秒) |
| expires | 过期日期 |
| httpOnly | 仅HTTP访问 |
| secure | 仅HTTPS |
| sameSite | 同站策略 |
| domain | 域名 |
| path | 路径 |
| signed | 签名 |
4.2 res.clearCookie() #
清除Cookie:
javascript
app.get('/clear-cookie', (req, res) => {
res.clearCookie('name');
res.send('Cookie已清除');
});
app.get('/clear-cookie-options', (req, res) => {
res.clearCookie('token', {
path: '/admin',
domain: 'example.com'
});
res.send('Cookie已清除');
});
五、链式调用 #
5.1 方法链 #
javascript
app.get('/chain', (req, res) => {
res.status(200)
.set('Content-Type', 'application/json')
.set('X-Custom-Header', 'value')
.json({ message: 'Success' });
});
5.2 完整示例 #
javascript
app.get('/api/users/:id', (req, res) => {
const user = getUserById(req.params.id);
if (!user) {
return res.status(404)
.json({ error: '用户不存在' });
}
res.status(200)
.set('Cache-Control', 'public, max-age=3600')
.json({
success: true,
data: user
});
});
六、响应格式化 #
6.1 统一响应格式 #
javascript
app.use((req, res, next) => {
res.success = (data, message = '成功') => {
res.json({
success: true,
data,
message
});
};
res.error = (message, code = 400) => {
res.status(code).json({
success: false,
error: message
});
};
res.paginate = (data, total, page, limit) => {
res.json({
success: true,
data,
pagination: {
total,
page,
limit,
totalPages: Math.ceil(total / limit)
}
});
};
next();
});
app.get('/users', (req, res) => {
res.success({ users: [] }, '获取用户列表成功');
});
app.get('/error', (req, res) => {
res.error('出错了', 400);
});
app.get('/posts', (req, res) => {
res.paginate([], 100, 1, 10);
});
6.2 API响应封装 #
javascript
class ApiResponse {
static success(res, data, message = '成功', statusCode = 200) {
return res.status(statusCode).json({
success: true,
data,
message
});
}
static error(res, message, statusCode = 400, errors = null) {
return res.status(statusCode).json({
success: false,
error: message,
errors
});
}
static paginated(res, data, total, page, limit) {
return res.json({
success: true,
data,
pagination: {
total,
page,
limit,
totalPages: Math.ceil(total / limit)
}
});
}
static created(res, data, message = '创建成功') {
return this.success(res, data, message, 201);
}
static noContent(res) {
return res.status(204).send();
}
static notFound(res, message = '资源未找到') {
return this.error(res, message, 404);
}
static unauthorized(res, message = '未授权') {
return this.error(res, message, 401);
}
static forbidden(res, message = '禁止访问') {
return this.error(res, message, 403);
}
}
app.get('/users', (req, res) => {
ApiResponse.success(res, { users: [] });
});
app.post('/users', (req, res) => {
ApiResponse.created(res, req.body);
});
app.get('/users/:id', (req, res) => {
const user = null;
if (!user) {
return ApiResponse.notFound(res, '用户不存在');
}
ApiResponse.success(res, user);
});
七、内容协商 #
7.1 res.format() #
根据Accept头返回不同格式:
javascript
app.get('/data', (req, res) => {
const data = { message: 'Hello' };
res.format({
'application/json': () => {
res.json(data);
},
'text/html': () => {
res.send(`<h1>${data.message}</h1>`);
},
'text/plain': () => {
res.send(data.message);
},
'default': () => {
res.status(406).send('Not Acceptable');
}
});
});
7.2 多格式API #
javascript
app.get('/users/:id', (req, res) => {
const user = { id: req.params.id, name: '张三' };
res.format({
json: () => res.json(user),
html: () => res.render('user', { user }),
xml: () => {
res.type('application/xml');
res.send(`<user><id>${user.id}</id><name>${user.name}</name></user>`);
},
default: () => res.json(user)
});
});
八、流式响应 #
8.1 流式输出 #
javascript
app.get('/stream', (req, res) => {
res.set('Content-Type', 'text/event-stream');
res.set('Cache-Control', 'no-cache');
res.set('Connection', 'keep-alive');
let counter = 0;
const interval = setInterval(() => {
res.write(`data: ${JSON.stringify({ count: counter++ })}\n\n`);
if (counter >= 10) {
clearInterval(interval);
res.end();
}
}, 1000);
req.on('close', () => {
clearInterval(interval);
});
});
8.2 文件流 #
javascript
const fs = require('fs');
app.get('/video', (req, res) => {
const videoPath = path.join(__dirname, 'video.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;
const chunksize = (end - start) + 1;
const file = fs.createReadStream(videoPath, { start, end });
res.writeHead(206, {
'Content-Range': `bytes ${start}-${end}/${fileSize}`,
'Accept-Ranges': 'bytes',
'Content-Length': chunksize,
'Content-Type': 'video/mp4'
});
file.pipe(res);
} else {
res.writeHead(200, {
'Content-Length': fileSize,
'Content-Type': 'video/mp4'
});
fs.createReadStream(videoPath).pipe(res);
}
});
九、缓存控制 #
9.1 设置缓存头 #
javascript
app.get('/cached', (req, res) => {
res.set('Cache-Control', 'public, max-age=3600');
res.json({ message: '可缓存1小时' });
});
app.get('/no-cache', (req, res) => {
res.set('Cache-Control', 'no-cache, no-store, must-revalidate');
res.json({ message: '不缓存' });
});
app.get('/etag', (req, res) => {
const data = { message: 'Hello' };
const etag = require('crypto')
.createHash('md5')
.update(JSON.stringify(data))
.digest('hex');
if (req.headers['if-none-match'] === etag) {
return res.status(304).end();
}
res.set('ETag', etag);
res.json(data);
});
十、完整示例 #
javascript
const express = require('express');
const path = require('path');
const app = express();
app.use(express.json());
app.use((req, res, next) => {
res.success = (data, message = '成功') => {
res.json({ success: true, data, message });
};
res.error = (message, code = 400) => {
res.status(code).json({ success: false, error: message });
};
next();
});
app.get('/', (req, res) => {
res.success({ message: 'Welcome to Express API' });
});
app.get('/users', (req, res) => {
res.success([
{ id: 1, name: '张三' },
{ id: 2, name: '李四' }
]);
});
app.get('/users/:id', (req, res) => {
res.success({ id: req.params.id, name: '张三' });
});
app.post('/users', (req, res) => {
res.status(201).success(req.body, '用户创建成功');
});
app.put('/users/:id', (req, res) => {
res.success({ id: req.params.id, ...req.body });
});
app.delete('/users/:id', (req, res) => {
res.status(204).send();
});
app.get('/download', (req, res) => {
const file = path.join(__dirname, 'files', 'document.pdf');
res.download(file);
});
app.use((req, res) => {
res.status(404).error('路由未找到', 404);
});
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).error('服务器错误', 500);
});
app.listen(3000);
十一、总结 #
Response对象要点:
| 方法 | 说明 |
|---|---|
| res.send() | 发送响应 |
| res.json() | 发送JSON |
| res.status() | 设置状态码 |
| res.redirect() | 重定向 |
| res.render() | 渲染模板 |
| res.sendFile() | 发送文件 |
| res.download() | 下载文件 |
| res.set() | 设置响应头 |
| res.cookie() | 设置Cookie |
| res.format() | 内容协商 |
下一步,让我们学习处理表单数据!
最后更新:2026-03-28