XMLHttpRequest.responseType:前端获取后端数据的一把“格式钥匙”
一、为什么是“钥匙”
浏览器收到 HTTP 响应后,原始形态永远只有两种:
- UTF-8 文本流
- 二进制字节流
前端真正想要的,可能是 JSON 对象、HTML DOM、Blob 下载链接、ArrayBuffer 纹理……
responseType 就是告诉浏览器:“请先帮我加工好,再交给我。”
不设它,默认只能拿到字符串,后续还得自己 parse、转码、拼 Blob,既啰嗦又容易踩坑。
二、6 种合法值全景图
(按“从文本到裸二进制”顺序,记忆更直观)
值 | 拿到的 xhr.response 类型 | 一句话场景 | 常见坑 |
---|---|---|---|
"" (默认) | String | 老式接口返回 JSON 字符串 | 忘记 JSON.parse 就直接当对象用,报 .map is not a function |
"text" | String | 同上,显式版 | 与 "" 完全等价,只是可读性更好 |
"json" | 已 parse 的 JS 对象/数组 | REST、GraphQL、JSONP 模拟 | 后端多写了个 BOM,parse 失败→response===null ,不会抛错! |
"document" | HTML/XML DOM | 拉取页面片段、SVG 图标 | 非 XML 会返回 null ;需要 xhr.response.documentElement |
"blob" | Blob | 下载图片、音视频、Excel | 旧 Android 4.4 以下不支持,需降级 "arraybuffer" 再 new Blob([buf]) |
"arraybuffer" | ArrayBuffer | WebGL 纹理、音频解码、WebAssembly | 不带 MIME,手动 new Blob([buf], {type}) 才能生成 URL |
三、一条时间线:从 XML 时代到二进制时代
- 2006 年以前:只有
""
和"document"
,世界全是 XML。 - 2008:XHR2 草案加入
"json"
、"blob"
、"arraybuffer"
,支持 Ajax 上传下载文件。 - 2012:Chrome 23 率先稳定支持全部 6 种值;IE10 跟进,IE9 及以下仅支持前 4 种。
- 2020:HTTP/2 普及,二进制帧+服务器推送,让
"arraybuffer"
/"blob"
用得更加频繁。
四、正确姿势 3 步法
- 先
open()
→ 2. 再设responseType
→ 3. 最后send()
const xhr = new XMLHttpRequest();
xhr.open('GET', '/api/export'); // 1
xhr.responseType = 'blob'; // 2 关键点
xhr.onload = () => {if (xhr.status === 200) {const url = URL.createObjectURL(xhr.response); // 已是 Blobconst a = document.createElement('a');a.href = url; a.download = 'report.xlsx';a.click();URL.revokeObjectURL(url);}
};
xhr.send(); // 3
反例:
xhr.send(); // ❌ 先发了
xhr.responseType = 'json' // ❌ 后设置,部分浏览器直接抛 InvalidStateError
五、跨域阴影:CORS 与 responseType 的隐藏限制
- 请求是 跨域 且服务器 没 返回
Access-Control-Allow-Origin:*
时,
浏览器只允许""
或"text"
,其余值会抛DOMException: InvalidAccessError
。 - 解决方案:
- 让后端加
Access-Control-Allow-Origin
- 或者走同源代理 / 网关转发
- 让后端加
六、调试锦囊
症状 | 检查点 |
---|---|
response === null | 1. 后端实际格式与 responseType 不符 2. JSON 含 BOM/语法错误 |
responseText 是空字符串 | 你设了 "blob" /"arraybuffer" ,浏览器不再保存文本副本 |
文件下载后损坏 | 后端返回 Content-Type: application/octet-stream 但用 "text" 接收,UTF-8 解码破坏二进制 |
七、与 Fetch 的“对照表”
XHR responseType Fetch 等价写法
"" | "text" await res.text()
"json" await res.json()
"blob" await res.blob()
"arraybuffer" await res.arrayBuffer()
"document" 无,需要 new DOMParser()
八、总结一句话
responseType 是 XMLHttpRequest 对“解析脏活”的封装。
选对了,后端数据一行代码就能用;选错,调试两小时起步。
记住顺序:先 open()
,再设类型,最后 send()
——
这把“格式钥匙”就算握稳了。