Request 对象 与 Response 对象 的对比总结
适用于典型的 Web 开发框架(如 Flask、Django、Express 等)中的通用概念:
| 特性 / 方面 | Request 对象 | Response 对象 |
|---|---|---|
| 作用 | 表示客户端向服务器发送的 HTTP 请求 | 表示服务器向客户端返回的 HTTP 响应 |
| 数据来源 | 客户端(浏览器、API 调用等) | 服务器(应用程序逻辑生成) |
| 包含内容 | - 请求方法(GET、POST 等) - URL - 请求头(Headers) - 查询参数(Query Parameters) - 路径参数(Path Parameters) - 请求体(Body,如表单、JSON) - Cookies - 客户端 IP、User-Agent 等 | - 响应状态码(200、404、500 等) - 响应头(Headers) - 响应体(Body,如 HTML、JSON、文件) - Cookies(设置到客户端) |
| 可读/可写性 | 通常为只读(用于读取客户端请求信息) | 通常可写(用于构造返回给客户端的内容) |
| 生命周期 | 在每次 HTTP 请求开始时创建 | 在处理完请求后构建并发送 |
| 常见使用场景 | - 获取用户提交的数据 - 验证身份(Token、Session) - 路由匹配 - 日志记录 | - 返回页面或 API 数据 - 设置 Cookie 或 Session - 重定向(3xx 状态码) - 错误提示 |
| 典型属性(以 Flask 为例) | request.method request.url request.args request.form request.json request.headers |
response.status_code response.headers response.set_cookie() response.data |
| 是否由开发者直接创建 | 否(由框架自动解析 HTTP 请求生成) | 通常由开发者构造(或由框架自动生成默认响应) |
💡 说明 :不同 Web 框架中 Request 和 Response 对象的具体 API 可能略有差异,但核心概念一致。
JavaScript 中的 Request 对象 和 Response 对象
在 JavaScript(特别是运行在 Web 环境中的 JavaScript) 中,Request 对象 和 Response 对象 主要出现在 Fetch API 的上下文中。它们是用于处理 HTTP 请求和响应的原生接口,常用于现代前端开发中替代传统的 XMLHttpRequest。
以下是针对 JavaScript 中的 Request 与 Response 对象 的详细对比表格:
| 特性 / 方面 | Request 对象 | Response 对象 |
|---|---|---|
| 所属标准 | Fetch API(由 WHATWG 定义) | Fetch API(由 WHATWG 定义) |
| 作用 | 表示一个 HTTP 请求,可被 fetch() 使用 |
表示一个 HTTP 响应,由 fetch() 返回的 Promise 解析得到 |
| 是否可构造 | ✅ 可通过 new Request(input[, init]) 创建 |
✅ 可通过 new Response([body, init]) 创建(常用于 Service Worker 或测试) |
| 典型创建方式 | js<br>const req = new Request('/api/data', { method: 'POST', body: JSON.stringify(data) });<br> |
js<br>fetch('/api/data')<br> .then(res => { /* res 是 Response 实例 */ });<br> |
| 主要只读属性 | - .method(如 'GET') - .url - .headers(Headers 对象) - .destination - .mode(cors, no-cors, same-origin) - .credentials |
- .status(如 200) - .statusText(如 "OK") - .ok(status 在 200--299 范围内为 true) - .url - .headers(Headers 对象) - .type(basic, cors, error 等) |
| 请求/响应体方法 | ❌ 通常不直接读取 body(但可通过 .clone() 后使用流) |
✅ 提供多种解析 body 的方法: - .json() - .text() - .blob() - .arrayBuffer() - .formData() |
| Body 可读次数 | Body 是 ReadableStream ,只能消费一次;需用 .clone() 复制后多次读取 |
同上:只能读取一次,多次读取需 .clone() |
| 常见使用场景 | - 自定义请求配置 - 在 Service Worker 中拦截并修改请求 - 缓存请求对象 | - 获取 API 返回数据 - 检查响应状态 - 在 Service Worker 中构造自定义响应 |
| 示例代码 | js<br>const request = new Request('https://api.example.com/users', {<br> method: 'GET',<br> headers: { 'Authorization': 'Bearer token' }<br>});<br>fetch(request);<br> |
js<br>fetch('/data.json')<br> .then(response => {<br> if (response.ok) return response.json();<br> throw new Error('Network error');<br> })<br> .then(data => console.log(data));<br> |
补充说明:
- 两者都实现了
Body接口 :因此都拥有.body(ReadableStream)、.bodyUsed等属性。 - 不可变性 :Request 和 Response 对象本身是不可变的 (immutable)。若需修改,必须创建新的实例(例如通过
new Request(oldRequest, { ... }))。 - Service Worker 中的核心角色 :在拦截网络请求时,
event.request是 Request 对象,而你可以返回一个自定义的 Response 对象。 - 与 Node.js 的区别 :上述内容适用于浏览器环境。在 Node.js 中(v18+),
fetch、Request、Response已作为全局 API 提供,行为基本一致。
JavaScript 中 new response() new request()
以下是 JavaScript 中 new Response() 与 new Request() 的详细对比表格,适用于浏览器及现代 Node.js(v18+)环境中的 Fetch API:
| 对比维度 | new Request(input[, init]) |
new Request() 示例 |
new Response([body, init]) |
new Response() 示例 |
|---|---|---|---|---|
| 用途 | 创建一个可复用的 HTTP 请求对象 | 模拟或封装请求,用于 fetch()、Service Worker 等 |
创建一个 HTTP 响应对象 | 在 Service Worker、测试或 mock 中返回自定义响应 |
| 是否必需参数 | ✅ input 必须(URL 字符串 或 另一个 Request 对象) |
new Request('/api/data') |
❌ 所有参数可选(可创建空响应) | new Response() → 返回空 body、状态 200 |
| 第一个参数 | - 字符串 URL - 或另一个 Request 实例(用于复制/修改) |
new Request('https://example.com') new Request(existingReq, { method: 'POST' }) |
- 响应体(string、Blob、ArrayBuffer、ReadableStream 等) - 若无 body,传 null 或省略 |
new Response(JSON.stringify({ok:1}), { headers: {'Content-Type':'application/json'} }) |
第二个参数 (init) |
可选配置对象: - method - headers - body - mode - credentials - cache - redirect 等 |
js<br>new Request('/login', {<br> method: 'POST',<br> body: JSON.stringify({user}),<br> headers: {'Content-Type': 'application/json'}<br>})<br> |
可选配置对象: - status - statusText - headers |
js<br>new Response('<h1>Offline</h1>', {<br> status: 503,<br> statusText: 'Service Unavailable',<br> headers: {'Content-Type': 'text/html'}<br>})<br> |
| 典型使用场景 | - 封装通用 API 请求 - 在 Service Worker 中修改/转发请求 - 缓存请求对象 | js<br>// Service Worker 中<br>const modifiedReq = new Request(event.request, {<br> headers: { ...event.request.headers, 'X-Custom': 'true' }<br>});<br> |
- Service Worker 返回离线页面 - 单元测试中 mock 响应 - 拦截并替换响应 | js<br>// Service Worker 离线兜底<br>return new Response('No network', { status: 503 });<br> |
| 是否可读取 body | 可通过 .text(), .json() 等方法读取(但通常不用于读取,而是作为请求发出) |
⚠️ Body 是流,只能消费一次;如需多次使用,先 .clone() |
✅ 主要用途就是提供 body 给客户端 | js<br>const res = new Response('hello');<br>res.text().then(t => console.log(t)); // 'hello'<br> |
| 实现接口 | 实现 Body 和 Request 接口 |
支持 .url, .method, .headers, .body, .bodyUsed 等 |
实现 Body 和 Response 接口 |
支持 .status, .ok, .headers, .body, .bodyUsed 等 |
| 不可变性 | ✅ 对象创建后属性不可变(修改需新建) | new Request(req, { method: 'PUT' }) |
✅ 同样不可变 | new Response(res.body, { status: 404 }) |
| 克隆方法 | .clone() → 返回新的 Request 实例 |
用于在缓存和网络中同时使用同一请求 | .clone() → 返回新的 Response 实例 |
用于同时返回响应和存入 Cache |
补充说明:
- 两者都继承自
Bodymixin,因此都拥有:.body(ReadableStream).bodyUsed(布尔值,表示 body 是否已被读取)- 方法:
.arrayBuffer(),.blob(),.formData(),.json(),.text()
- 不能直接修改 headers :需在
init中传入新Headers对象,或通过构造新实例覆盖。 - 在 Service Worker 中极其重要:
event.request是Request实例event.respondWith()必须传入Response实例
✅ 一句话总结:
new Request()用于构造请求 ,new Response()用于构造响应,二者是 Fetch API 中实现灵活网络控制(尤其是离线能力)的基石。
如何在 Service Worker、缓存策略 或 错误处理 中使用这两个对象
在 Service Worker 中,Request 和 Response 对象是实现离线支持、缓存策略和错误处理的核心。
下面从三个方面详细说明如何使用它们:
一、在 Service Worker 中使用 Request/Response
1. 拦截请求(fetch 事件)
Service Worker 通过监听 fetch 事件,可以拦截所有页面发出的网络请求。
javascript
self.addEventListener('fetch', (event) => {
const request = event.request; // ← 这是一个 Request 对象
// 使用 respondWith() 返回一个 Response 对象或 Promise<Response>
event.respondWith(
caches.match(request).then(cached => {
// 如果缓存中有,返回缓存
if (cached) return cached;
// 否则走网络
return fetch(request).then(networkResponse => {
// 克隆响应(因为流只能读一次)
const clone = networkResponse.clone();
caches.open('v1').then(cache => cache.put(request, clone));
return networkResponse;
});
})
);
});
✅ 关键点:
event.request是只读的Request对象。event.respondWith()必须传入一个Response对象或返回它的 Promise。
二、常见缓存策略(结合 Request/Response)
以下是几种经典缓存策略的实现方式:
1. Cache First(缓存优先)
适用于静态资源(如图片、CSS、JS)。
javascript
async function cacheFirst(request) {
const cache = await caches.open('static-cache');
const cached = await cache.match(request);
return cached || await fetch(request);
}
2. Network First(网络优先)
适用于动态内容(如 API),失败时回退到缓存。
javascript
async function networkFirst(request) {
try {
const networkResponse = await fetch(request);
// 更新缓存
caches.open('api-cache').then(cache => cache.put(request, networkResponse.clone()));
return networkResponse;
} catch (error) {
// 网络失败,尝试返回缓存
const cache = await caches.open('api-cache');
const cached = await cache.match(request);
return cached || new Response('Offline', { status: 503 });
}
}
3. Stale-While-Revalidate(过期仍可用 + 后台更新)
立即返回缓存(即使过期),同时后台更新缓存。
javascript
async function staleWhileRevalidate(request) {
const cache = await caches.open('swr-cache');
const cached = await cache.match(request);
// 立即返回缓存(如果有)
fetch(request).then(networkResponse => {
cache.put(request, networkResponse.clone()); // 后台更新
});
return cached || await fetch(request);
}
🔁 所有策略中,必须克隆 Response (
.clone())才能既返回给页面又存入缓存,因为 Body 是流,只能消费一次。
三、错误处理(自定义 Response)
当网络失败或资源不存在时,可返回自定义的 Response 对象。
1. 返回离线页面
javascript
self.addEventListener('fetch', event => {
event.respondWith(
fetch(event.request).catch(() => {
// 返回自定义离线 HTML
return caches.match('/offline.html')
.then(res => res || new Response('<h1>You are offline</h1>', {
headers: { 'Content-Type': 'text/html' }
}));
})
);
});
2. 返回 JSON 错误(用于 API 请求)
javascript
// 在 networkFirst 策略中
catch (err) {
if (request.destination === 'empty') { // 判断是否为 fetch API 调用(非导航)
return new Response(JSON.stringify({ error: 'Offline' }), {
status: 503,
headers: { 'Content-Type': 'application/json' }
});
}
// 否则返回 HTML 离线页
}
3. 处理无效请求(如跨域、不安全方法)
javascript
if (request.method !== 'GET') {
return fetch(request); // 非 GET 请求绕过缓存
}
// 或拒绝某些路径
if (request.url.includes('/admin')) {
return new Response('Forbidden', { status: 403 });
}
四、实用技巧
| 场景 | 技巧 |
|---|---|
| 区分请求类型 | 使用 request.destination: ''(fetch API)、'document'(页面)、'image'、'script' 等 |
| 避免缓存 POST 请求 | 只缓存 GET 请求: if (request.method !== 'GET') return fetch(request); |
| 防止缓存爆炸 | 定期清理旧缓存: 在 activate 事件中删除旧 cache 名称 |
| 克隆的重要性 | 响应体是流,一旦读取就无法再次使用,所以: const clone = response.clone(); cache.put(req, clone); return response; |
总结
| 功能 | 如何使用 Request/Response |
|---|---|
| 拦截请求 | event.request 是 Request;respondWith(Response) 返回响应 |
| 缓存策略 | 用 caches.match(request) 查缓存,cache.put(request, response.clone()) 存响应 |
| 错误兜底 | fetch().catch() 中返回 new Response(...) 自定义错误页或 JSON |
| 性能优化 | 通过克隆、按类型区分策略、限制缓存范围提升体验 |
如果你正在开发 PWA(渐进式 Web 应用),这些模式是实现离线可用性 和快速加载的关键。