Request 和 Response 对比总结 以及在 Service Worker、缓存策略、错误处理中使用

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+),fetchRequestResponse 已作为全局 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' }) - 响应体(stringBlobArrayBufferReadableStream 等) - 若无 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>
实现接口 实现 BodyRequest 接口 支持 .url, .method, .headers, .body, .bodyUsed 实现 BodyResponse 接口 支持 .status, .ok, .headers, .body, .bodyUsed
不可变性 ✅ 对象创建后属性不可变(修改需新建) new Request(req, { method: 'PUT' }) ✅ 同样不可变 new Response(res.body, { status: 404 })
克隆方法 .clone() → 返回新的 Request 实例 用于在缓存和网络中同时使用同一请求 .clone() → 返回新的 Response 实例 用于同时返回响应和存入 Cache

补充说明:

  • 两者都继承自 Body mixin,因此都拥有:
    • .body(ReadableStream)
    • .bodyUsed(布尔值,表示 body 是否已被读取)
    • 方法:.arrayBuffer(), .blob(), .formData(), .json(), .text()
  • 不能直接修改 headers :需在 init 中传入新 Headers 对象,或通过构造新实例覆盖。
  • 在 Service Worker 中极其重要
    • event.requestRequest 实例
    • event.respondWith() 必须传入 Response 实例

一句话总结

new Request() 用于构造请求new Response() 用于构造响应,二者是 Fetch API 中实现灵活网络控制(尤其是离线能力)的基石。


如何在 Service Worker、缓存策略 或 错误处理 中使用这两个对象


Service Worker 中,RequestResponse 对象是实现离线支持、缓存策略和错误处理的核心。

下面从三个方面详细说明如何使用它们:


一、在 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 应用),这些模式是实现离线可用性快速加载的关键。

相关推荐
教练、我想打篮球7 天前
119 response.setCharacterEncoding(“utf8“) 设置编码之后 编码依然为 ISO-8859-1
乱码·response·encoding
曲幽10 天前
Flask核心技能:从零上手视图函数
python·json·app·web·get·post·request·response
曲幽12 天前
Flask进阶必备:掌握中间件、钩子和扩展
python·flask·web·request·cors·wsgi
闲人编程1 个月前
从零开发一个简单的Web爬虫(使用Requests和BeautifulSoup)
前端·爬虫·beautifulsoup·bs4·web·request·codecapsule
Irene19912 个月前
Request 和 Response 都使用了 Fetch API 的 Body 混入
request·response·body混入
深蓝电商API3 个月前
Requests 库详解:爬虫工程师的 “瑞士军刀”
爬虫·request
Ice__Cai4 个月前
Flask 之 Request 对象详解:全面掌握请求数据处理
后端·python·flask·request·python web框架
天若有情6735 个月前
【python】Python爬虫入门教程:使用requests库
开发语言·爬虫·python·网络爬虫·request
wsdhla8 个月前
form表单提交前设置请求头request header及文件下载
html·form·request·send·header·submit