post 请求下载文件
文章首发于个人网站
背景
最近遇到一个下载的需求,由于 url 参数太长(常用的下载方法 a 标签或者 location.href 的方法都是 get 请求,get 请求参数长度有限制),无法下载,考虑了好几种方案,最终还是觉得通过 ajax 的 POST 方法进行下载,比较容易实现,下面记录实现过程以及遇到的问题。
但是由于 AJAX
并不会唤起浏览器的下载窗口,AJAX
设计的初衷就是用来实现异步刷新
的,用以改善原始的 form 表单提交刷新页面的问题,那么如何来解决呢?
POST 方法下载实现原理
通过 fetch 请求获取文件,然后利用 Blob 对象来接收处理,在接收到后端返回的文件后,把其转化一下,放入a标签
的href
中,并触发下载行为。
实现的代码如下:
fetch(url, {method: 'POST',body: JSON.stringify(params),header: {'Content-Type': 'application/json;charset=UTF-8'}
}).then(function(response) {return response.blob();
}).then(function(blob) {const link = document.createElement('a')link.style.display = 'none'link.href = URL.createObjectURL(blob)document.body.appendChild(link)link.click()// 释放的 URL 对象以及移除 a 标签URL.revokeObjectURL(link.href)document.body.removeChild(link)
});
这里需要注意的是要记得要调用 response 的 blob 方法,这样才会返回一个 blob,如果你没用过 blob 的话,可能你以前只知道 json 和 text,其实 response 的 body 还可以转化为 arrayBuffer
和 formData
。
具体 Response 可以见 MDN
如何拿到文件名
可以下载文件了只是第一步,但是你会发现还有一个问题,下载下来的文件名是你看不懂的名字,类似这样:
我这边的方案是把文件名放在 response 的 headers 里,放在 content-disposition 字段里,有个 fileName 字段,用来存放文件名。
我感觉在下载文件的时候 content-disposition 字段对于他们后端来说感觉是都会加的,因为最开始我用 get 下载的时候就已经有这个字段了,如果你们后端没有设置这个 header ,可以设置一下,当然也可以设置到其他字段里。
一个小插曲
当我把 fetch 后的 res 打印出来看 Response 的时候,发现 headers 里是空对象,如下:
然后我再通过 res.headers
直接去拿 headers,发现还是一个 Headers 的空对象。
我还以为 headers 里面没有东西,但是当我直接通过 res.headers.get('content-disposition')
去拿的时候,竟然拿到了,数据像这样:
attachment;fileName=%E7%9B%B4%E6%92%AD%E6%97%B6%E9%95%BF%E4%B8%BB%E6%92%AD%E6%98%8E%E7%BB%86.xls
然后你就可以通过多种方式将文件名给提取出来,我这里采用的是通过 split
方法来提取的。
res.headers.get('content-disposition').split(';')[1].split('=')[1]
最终的实现
准备工作都做好了,然后就写出了这样的代码:
fetch(url, {method: 'POST',body: JSON.stringify(params),header: {'Content-Type': 'application/json;charset=UTF-8'}
}).then(function(response) {const filename = res.headers.get('content-disposition').split(';')[1].split('=')[1]return {filename,blob: response.blob()}
}).then(function(obj) {const link = document.createElement('a')link.style.display = 'none'// a 标签的 download 属性就是下载下来的文件名link.download = obj.filenamelink.href = URL.createObjectURL(obj.blob)document.body.appendChild(link)link.click()// 释放的 URL 对象以及移除 a 标签URL.revokeObjectURL(link.href)document.body.removeChild(link)
});
本以为就可以了,但是下载下来打开 excel 发现内容是 Promise,然后才发现原来 response.blob()
返回的是一个 promise。
所以改进的实现方案如下:
fetch(url, {method: 'POST',body: JSON.stringify(params),header: {'Content-Type': 'application/json;charset=UTF-8'}
}).then(function(response) {const filename = res.headers.get('content-disposition').split(';')[1].split('=')[1]response.blob().then(blob => {const link = document.createElement('a')link.style.display = 'none'// a 标签的 download 属性就是下载下来的文件名link.download = filenamelink.href = URL.createObjectURL(blob)document.body.appendChild(link)link.click()// 释放的 URL 对象以及移除 a 标签URL.revokeObjectURL(link.href)document.body.removeChild(link)})
})
不过这种 then 里面又套了 then ,看着有点不好看,所以用 async/await 重新写了一版:
async function postDownload(url, params) {const request = {body: JSON.stringify(params),method: 'POST',headers: {'Content-Type': 'application/json;charset=UTF-8'}}const response = await fetch(url, request)const filename = response.headers.get('content-disposition').split(';')[1].split('=')[1]const blob = await response.blob()const link = document.createElement('a')link.download = decodeURIComponent(filename)link.style.display = 'none'link.href = URL.createObjectURL(blob)document.body.appendChild(link)link.click()URL.revokeObjectURL(link.href)document.body.removeChild(link)j
}
这个函数里没有写任何的错误处理,那也不是这篇文章要讲的,不过自己在实现的时候应该加上 try/catch,不然如果有问题,不报错还是很难受的。
有兴趣可以关注我的微信公众号「前端桃园」
post 请求下载文件相关推荐
- php post请求 下载文件,POST请求 下载文件
通过axios发送POST请求 下载文件. 这时候的 Content-Type: application/json;charset=UTF-8 先贴axios({ method: 'post', ur ...
- jquery ajax post请求下载文件
第一次用ajax post请求下载文件 ,之前一直用vue的写,今天用同样方式发现是乱码,走了不少弯路,特此记录下方法 var outData = getData() //传参数据var url = ...
- post请求下载文件(兼容IE)
post请求下载文件(兼容IE) 有时候由于下载文件的url携带的参数过多,导致整个url长度超过get请求的上限,这个时候需要更换为post请求,具体实现如下 function downLoadFi ...
- 【post请求下载文件流】如何使用post请求下载文件流 blob
最近有个需求,做文件的下载.其实下载没什么要特别说的,之前都是用的get请求,这次不同,后台用的post请求,返回的是数据流,这种post请求下载文件的方式倒是没怎么弄过.记录一下. 接口 接口地址为 ...
- js post请求下载文件
js 下载post请求的文件 /* content 文件二进制内容 fileName 文件名 */ downloadFile(content, fileName) {(fileName &&a ...
- ajax请求文件下载 php,使用Ajax请求下载文件
要使浏览器下载一个文件,您需要这样做:function downloadFile(urlToSend) { var req = new XMLHttpRequest(); req.open(" ...
- 实战PyQt5: 130-使用HTTP请求下载文件
在桌面应用中,往往需要从网络获取一些数据,比如下某个图像或者文本文件,查询城市天气预报,加载网络地图等等.在Qt中,提供一些网络处理类,可以很方便地实现上面列出的需求.核心类QNetworkAcces ...
- vue中使用post请求下载文件
fetch(url+(携带的参数), { method: "POST", headers: { 'Content-Type':'application/x-www-form-url ...
- Java 前端请求下载文件
- http协议请求部首详解以及用c++写socket下载文件
本篇博文将介绍几个我认为比较有作用的请求部首 Connection ,这个部首常见的值是keep-alive 和close.close的意思是说,我发一次请求,你回复给我消息,那么咱俩就立刻断开,等我 ...
最新文章
- python GIL :全局解释器
- 【计算机网络】传输层 : TCP 可靠传输 ( 可靠传输机制 | 快速重传机制 )
- 三星a7支持html吗,三星A7怎么样 三星A7特点介绍
- jQuery工具和方法(二)
- u3d文件上传至服务器,unity 上传图片到云服务器
- 用python玩转数据慕课答案第三周_大学慕课用Python玩转数据答案公众号
- C语言第七讲,函数入门.
- VMware三种工作模式
- Python map/reduce/filter/sorted函数以及匿名函数
- 测试软件测显卡有啸叫,完美解决 显卡电流声!显卡啸叫!吱吱的电流声!附解决方案!...
- Mybatis提高查询效率的方式
- Ubuntu 图标主题 Nitrux 升级
- 055 集体照 (25 分)
- 三星 c5 html,三星GALAXY C5/C7参数配置介绍 均支持Samsung Pay
- SM2 SM3 SM4 国密版本,基于bouncycastle 实现
- 大学毕业生参考信函提示
- 探索AI助手ChatGPT实际应用场景
- mysql 删除重复_MySQL查询和删除重复记录
- Maximum Profit(C++最大利益简单算法)
- java中使用tika_【Tika基础教程之中的一个】Tika基础教程
热门文章
- 杭电ACM2000题
- 了解开源图表组件FusionChartsFree
- 在计算机英语中 input的意思是,计算机英语词汇解释
- ios刺客信条一直显示连接服务器,刺客信条本色iOS进不去怎么办
- 未来生活进行时: 畅想未来新兴技术40年——百大趋势性技术汇总(上)
- 决策支持系统 (Decision-making Support System, DSS) (人机智能系统)
- 计算机网络技术毕业生实习报告_计算机网络专业毕业实习报告
- Java多线程编程-停止线程 暂停线程
- php怎么把多个pdf拼接成一个,两张pdf合并成一页 怎么将pdf文件中的页面进行拼接?两页或多页pdf拼接...
- 批处理批量卸载微软补丁