create-react-app项目调用API无法获取Content-Disposition响应头
问题原因
这是浏览器CORS策略的默认限制:前端JavaScript通过fetch/XMLHttpRequest发起跨域请求时,默认只能读取以下6个基础响应头:
- Cache-Control
- Content-Language
- Content-Type
- Expires
- Last-Modified
- Pragma
Content-Disposition不属于基础响应头范畴,所以即使响应头真实存在,也无法直接被JS读取。Postman不受CORS策略限制,Chrome开发者工具的网络面板会展示所有原始响应头,因此你能在这两个场景下看到该头。
解决步骤
步骤1:配置响应头暴露规则
你需要在返回响应的服务端显式添加Access-Control-Expose-Headers头,指定允许前端读取的非基础响应头,有两种配置场景:
- 如果可以直接修改后端API服务配置,直接给接口响应添加头:
Access-Control-Expose-Headers: Content-Disposition
- 如果不方便改后端,直接在你用来做代理的express层配置即可,以CRA常用的
http-proxy-middleware代理配置(src/setupProxy.js)为例:
const { createProxyMiddleware } = require('http-proxy-middleware'); module.exports = function(app) { app.use( '/api', // 替换为你的接口匹配规则 createProxyMiddleware({ target: 'http://你的后端服务地址', changeOrigin: true, // 代理收到后端响应后,添加暴露头规则 onProxyRes: (proxyRes) => { proxyRes.headers['Access-Control-Expose-Headers'] = 'Content-Disposition'; } }) ); };
步骤2:调整前端下载代码
优化文件名提取逻辑,兼容中文文件名转码、边界异常处理,同时新增blob资源释放避免内存泄漏:
let filename = 'test-file-name'; fetch(transactionReportPath(), { headers: { accept: 'text/csv', Authorization: `Bearer ${getToken()}` } }) .then((res) => { const disposition = res.headers.get('Content-Disposition'); // 匹配响应头中的文件名规则 if (disposition) { const matchRes = disposition.match(/filename\*?=['"]?(?:UTF-8'')?([^;'"]*)['"]?/i); if (matchRes?.[1]) { // 解码处理中文文件名 filename = decodeURIComponent(matchRes[1]); } } return res.blob() }) .then((blob) => { const file = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = file; a.download = filename; document.body.appendChild(a); a.click(); a.remove(); // 释放blob占用的内存资源 window.URL.revokeObjectURL(file); });
内容的提问来源于stack exchange,提问作者vrunnn
相关产品推荐
相关产品推荐

