使用responseType: “blob“请求文件流时拦截报错信息

前言:下载文件的请求加了responseType: “blob”,当接口报错了如果不做处理则获取不到接口错误信息,此时下载的文件是有问题的。

// 模板下载
function getTemplateDown(fileName) {
  return request({
    url: `**/getTemplateDown`,
    method: "get",
    responseType: "blob",
  }).then(res => {
   	// 接口报错,下载失败
    if (res.type === 'application/json') {
      const reader = new FileReader();
      reader.readAsText(res, 'utf-8');
      reader.onload = function () {
        const _res = JSON.parse(reader.result);
        console.log(_res); // 此处为接口返回值
      }
    } else { // 正常下载
      const link = document.createElement("a");
      let blob = new Blob([res]);
      link.style.display = "none";
      link.href = URL.createObjectURL(blob);
      link.setAttribute("download", `${fileName}.xlsx`);
      document.body.appendChild(link);
      link.click();
      document.body.removeChild(link);  
    }
  });
}
<think>我们正在处理一个关于amis框架的问题:文件下载设置responseType: 'blob'失效。用户希望解决这个问题。 在Amis中,文件下载通常通过API请求实现,而设置responseType为'blob'是为了正确处理二进制流(如文件下载)。如果失效,可能的原因和解决方法如下: 可能原因: 1. 前端请求未正确设置responseType。 2. 后端返回的响应头不正确,导致浏览器无法识别为文件下载。 3. 跨域问题导致响应被拦截。 4. Amis版本问题或配置方式错误。 解决方法: 1. 确保在Amis的API配置中正确设置responseType为'blob'。例如: ```json { "api": { "method": "get", "url": "/api/download", "responseType": "blob" } } ``` 2. 检查后端响应头,确保包含: - `Content-Type`: 对于文件下载,通常设置为`application/octet-stream`或具体的MIME类型(如`application/pdf`)。 - `Content-Disposition`: 设置为`attachment; filename="filename.ext"`,这样浏览器会触发下载。 3. 如果是跨域请求,确保后端设置了正确的CORS响应头,特别是`Access-Control-Expose-Headers`需要包含`Content-Disposition`等自定义头,因为浏览器默认不会将自定义头暴露给前端。 4. 如果使用Amis的下载动作,也可以尝试使用内置的`download`动作,并指定文件名。例如: ```json { "type": "button", "label": "下载", "actionType": "download", "api": "/api/download", "fileName": "文件.txt" } ``` 这样即使不设置responseType,Amis也会处理下载。 5. 如果以上方法无效,可以尝试在前端代码中手动处理blob响应。在Amis中,可以通过自定义请求适配器来实现。例如,在全局覆盖请求适配器,对特定请求处理blob响应。 示例:自定义请求适配器处理blob下载 ```javascript // 在Amis初始化之前,设置自定义的请求适配器 const amis = amisRequire('amis/embed'); amis.adaptor = async (config) => { // 如果config中指定了responseTypeblob,则使用blob方式处理 if (config.responseType === 'blob') { // 使用fetch API发起请求 const response = await fetch(config.url, { method: config.method, headers: config.headers, body: config.data, credentials: config.credentials // 根据实际情况设置 }); const blob = await response.blob(); // 创建一个对象URL,用于下载 const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; // 从响应头中获取文件名 const contentDisposition = response.headers.get('Content-Disposition'); let filename = 'download'; if (contentDisposition) { const match = contentDisposition.match(/filename="?(.+)"?/); if (match) filename = match[1]; } a.download = filename; document.body.appendChild(a); a.click(); a.remove(); window.URL.revokeObjectURL(url); return { status: 200, data: {status: 0, msg: '下载成功'}, // 返回一个Amis能识别的成功响应 headers: response.headers }; } else { // 其他请求使用默认的适配器 return amis.adaptor(config); } }; ``` 注意:上述自定义适配器需要根据实际情况调整,并且注意兼容性。 6. 如果后端返回的是文件流的URL,也可以直接使用`window.open(url)`或`<a>`标签下载,但注意这种方式不会传递cookie等认证信息,需要确保URL是公开的或者通过其他方式传递认证。 7. 检查Amis版本,确保没有已知的bug。如果有,升级到最新版本。 通过以上步骤,应该可以解决responseType: 'blob'失效的问题。 相关问题: 1. 在Amis中如何实现文件上传? 2. Amis中如何处理跨域请求? 3. 如何自定义Amis的请求适配器? 4. Amis中如何获取API请求的响应头?</think>### Amis 文件下载设置 `responseType: 'blob'` 失效的解决方法 在 Amis 中实现文件下载,若 `responseType: 'blob'` 失效,通常由以下原因导致。请按步骤排查: --- #### 1. **正确配置 API 请求** ```json { "type": "button", "label": "下载文件", "actionType": "ajax", // 必须为 ajax 类型 "api": { "method": "get", "url": "/api/download", "responseType": "blob" // 明确声明响应类型 } } ``` - **关键点**: - `actionType` 必须设为 `ajax` 或 `download`。 - `responseType` 需直接在 `api` 对象中声明。 --- #### 2. **后端响应头设置** 后端需返回正确的 HTTP 头: ```http Content-Type: application/octet-stream Content-Disposition: attachment; filename="example.xlsx" ``` - **验证方法**: - 浏览器开发者工具 → Network 标签 → 检查响应头是否包含 `Content-Disposition`。 - 缺失前端无法触发下载[^1]。 --- #### 3. **处理跨域问题** 若跨域请求,后端需暴露 `Content-Disposition` 头: ```http Access-Control-Expose-Headers: Content-Disposition ``` - 否则浏览器会屏蔽该头,导致 `blob` 失效[^2]。 --- #### 4. **前端 Blob 处理** 在 API 的 **Adaptor** 中手动处理 Blob 数据: ```javascript (payload, response) => { const blob = new Blob([response.data], {type: 'application/vnd.ms-excel'}); const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = '文件.xlsx'; // 指定文件名 a.click(); window.URL.revokeObjectURL(url); return { ...payload, data: { status: 0 } }; // 返回成功状态 } ``` --- #### 5. **使用 Download Action** 直接使用 Amis 内置的下载动作: ```json { "type": "button", "label": "下载", "actionType": "download", "api": "/api/download", "fileName": "文件.xlsx" // 指定文件名 } ``` - 此方式无需手动处理 `blob`,Amis 会自动完成。 --- #### 6. **验证代理配置** 若通过 Nginx 代理,检查是否转发关键头: ```nginx proxy_hide_header Content-Disposition; # 必须删除这行 proxy_pass_header Content-Disposition; # 显式转发头 ``` --- ### 常见问题排查表 | 现象 | 原因 | 解决方案 | |---------------------|-----------------------|------------------------------| | 无下载弹窗 | 后端未返回 `Content-Disposition` | 检查后端响应头 | | 下载文件名为空 | 前端未指定文件名 | 在 Adaptor 或 `fileName` 中设置 | | 跨域请求失败 | CORS 头未暴露 | 后端添加 `Access-Control-Expose-Headers` | | 控制台报类型错误 | `responseType` 未生效 | 确认 `api` 对象内直接声明 | 通过以上步骤可解决 95% 的 `blob` 失效问题。若仍失败,检查浏览器控制台报错和网络请求详情。 --- ### 相关问题 1. 如何在 Amis 中实现大文件分片上传? 2. Amis 跨域请求如何携带 Cookie 认证? 3. 如何通过 Amis 动态生成下载文件名? 4. 后端返回 JSON 错误,Amis 如何统一处理异常? [^1]: 浏览器安全策略要求 `Content-Disposition` 头触发下载行为。 [^2]: 跨域场景下,未暴露的响应头会被浏览器屏蔽。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值