Skip to content

Request 与 Response

fetch 体系里,请求和响应不是单纯的文本结果,而是两个正式对象:

  • Request
  • Response

理解它们之后,很多 fetch、缓存、Service Worker、流式读取相关代码会更容易看懂。

Request 是什么

Request 表示一次请求本身,里面会带着:

  • URL
  • method
  • headers
  • body
  • mode
  • credentials
  • cache
  • redirect
js
const request = new Request('/api/users', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ page: 1 }),
})

它可以直接传给 fetch

js
const response = await fetch(request)

Response 是什么

Response 表示一次响应对象。

js
const response = await fetch('/api/users')

console.log(response.status)
console.log(response.ok)
console.log(response.headers.get('content-type'))

它不只是“响应体内容”,还包含状态码、响应头、是否重定向等信息。

常用属性先记住哪些

Request

最常见的是:

  • request.url
  • request.method
  • request.headers
js
const request = new Request('/api/users', {
  method: 'POST',
  body: JSON.stringify({ name: 'Tom' }),
})

console.log(request.method)
console.log(request.url)

Response

最常见的是:

  • response.ok
  • response.status
  • response.statusText
  • response.headers
  • response.url
js
const response = await fetch('/api/users')

console.log(response.ok)
console.log(response.status)
console.log(response.statusText)
console.log(response.url)

其中:

  • ok 一般表示是否是 2xx
  • status 是 HTTP 状态码

读取响应体

最常见的还是从 Response 里取数据:

js
const response = await fetch('/api/users')
const data = await response.json()

常见读取方法包括:

  • json()
  • text()
  • blob()
  • arrayBuffer()
  • formData()

请求体和响应体为什么常说“只能读一次”

因为底层 body 通常是流,一旦消费过,就不能再按原样重复读。

js
const response = await fetch('/api/users')
await response.json()
// await response.text() // 再读通常就不行了

这也是 fetch 体系里很容易踩的坑。

为什么有时需要 clone()

如果同一个响应既想给页面用,又想额外做缓存或日志,就需要复制一份。

js
const response = await fetch('/api/users')
const copy = response.clone()

const data = await response.json()
const text = await copy.text()

这在 Service Worker 里尤其常见。

也可以手动创建 Request

js
const request = new Request('https://api.example.com/users', {
  method: 'GET',
  headers: {
    Accept: 'application/json',
  },
})

这适合:

  • 提前封装请求对象
  • 在拦截链里传递请求

也可以手动创建 Response

js
const response = new Response(JSON.stringify({ ok: true }), {
  status: 200,
  headers: {
    'Content-Type': 'application/json',
  },
})

这在模拟响应、缓存代理、Service Worker 返回自定义结果时很常见。

Headers

Headers 是专门处理请求头和响应头的对象接口。

js
const headers = new Headers()
headers.set('Content-Type', 'application/json')
headers.set('Authorization', 'Bearer token')

也可以从响应里读:

js
const response = await fetch('/api/users')
console.log(response.headers.get('content-type'))

和 XHR 的区别

相比 XMLHttpRequestfetch 体系更偏:

  • 对象化
  • 流式化
  • 可组合

所以 Request / Response / Headers 更适合做中间层封装,而不只是简单发请求。

使用建议

  • Request 理解成“请求对象”,把 Response 理解成“响应对象”。
  • 读取 body 前先想清楚是否后面还要复用。
  • 需要重复消费时,用 clone()
  • 看到 Service Worker、缓存代理、流式读取时,优先联想到 RequestResponse 模型。

基于 MIT 许可发布