主题
Fetch 进阶
fetch 的基础用法并不复杂,但在真实项目里更常见的问题是:如何处理鉴权、跨域、取消请求、超时、错误状态和请求体格式。
基本结构
js
const response = await fetch('/api/users', {
method: 'GET',
})
if (!response.ok) {
throw new Error(`HTTP ${response.status}`)
}
const data = await response.json()fetch 只会在什么情况下 reject
fetch 并不会因为 404、500 自动进入 catch,只有网络层失败时才会 reject,例如:
- DNS 解析失败
- 断网
- 请求被主动取消
- 浏览器策略阻止请求
所以业务代码里通常要手动检查 response.ok。
js
fetch('/api/user')
.then((response) => {
if (!response.ok) {
throw new Error(`HTTP ${response.status}`)
}
return response.json()
})
.catch((error) => {
console.error(error)
})常用配置项
headers
js
fetch('/api/user', {
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json',
},
})body
发送 JSON:
js
fetch('/api/user', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ name: 'Tom' }),
})发送 FormData:
js
const formData = new FormData()
formData.append('file', file)
fetch('/upload', {
method: 'POST',
body: formData,
})发送 FormData 时,不要手动设置 Content-Type,让浏览器自动补 boundary。
credentials
用于控制请求是否携带 Cookie、HTTP 认证信息等凭证。
same-origin:默认值,仅同源请求携带。include:跨域请求也允许携带凭证。omit:不携带凭证。
js
fetch('https://api.example.com/user', {
credentials: 'include',
})如果跨域请求要携带 Cookie,服务端还需要配合:
Access-Control-Allow-Credentials: trueAccess-Control-Allow-Origin不能是*
mode
控制请求模式,常见值有:
cors:默认跨域请求模式。same-origin:只允许同源。no-cors:能力非常受限,通常只适合某些上报场景。
js
fetch('https://api.example.com/data', {
mode: 'cors',
})cache
控制浏览器缓存策略:
defaultno-storereloadno-cacheforce-cacheonly-if-cached
js
fetch('/api/list', {
cache: 'no-store',
})redirect
控制重定向行为:
follow:默认,自动跟随。error:遇到重定向直接报错。manual:手动处理。
js
fetch('/login', {
redirect: 'error',
})请求取消
可结合 AbortController 使用:
js
const controller = new AbortController()
fetch('/api/list', {
signal: controller.signal,
})
controller.abort()超时控制
fetch 本身没有原生 timeout 选项,通常自己封装:
js
async function fetchWithTimeout(url, options = {}, timeout = 5000) {
const controller = new AbortController()
const timer = setTimeout(() => controller.abort(), timeout)
try {
return await fetch(url, {
...options,
signal: controller.signal,
})
} finally {
clearTimeout(timer)
}
}读取响应体
响应体只能消费一次。
js
const response = await fetch('/api/user')
const data = await response.json()
// const text = await response.text() // 再次读取会失败常见读取方式:
response.json()response.text()response.blob()response.arrayBuffer()response.formData()
常见封装思路
js
async function request(url, options) {
const response = await fetch(url, options)
if (!response.ok) {
const message = await response.text()
throw new Error(message || `HTTP ${response.status}`)
}
return response.json()
}使用建议
- 统一检查
response.ok,不要只靠catch。 - 有登录态的跨域请求,优先明确写出
credentials。 - 请求存在竞态时,配合
AbortController取消旧请求。 - 上传文件时直接传
FormData,不要手动拼multipart/form-data。
