摘要:如果像本例中这样的场景会遇到这样一个问题,详见链接当请求参数过长或为了安全,就需要用到下载。写到这里自己都忍不住想锤自己,给自己挖坑不说,这样来回请求下载,流量,真的是败家。
这几天一直在做远程文件下载的事,现在总算有了解决,特来记录一下踩过的坑和想揍自己的心
需求应用场景是这样的,底层逻辑数据请求接口是由Java写的,也就是说原始文件存在Java服务端,返回时有加密措施
由于工作需要,前端获取数据操作需要node服务器做中间转发
Java接口使用post方式来请求下载
前端点击下载后浏览器启用内置下载器进行下载,并能看到进度如下图所示
先说总结,下附过程前端GET下载和POST下载的对比
一般情况下,如果是网盘应用或者不涉及多文件下载的场景(如本例中node作为文件服务器,可以直接与前端交互时),完全可以通过拼接GET请求url进行模拟点击下载,系统开销还小,响应快。如果像本例中这样的场景会遇到这样一个问题,详见链接
当请求参数过长或为了安全,就需要用到POST下载。
最终采用的方案前端通过模拟表单提交POST请求
node端通过pipe将responseA和responseB串联起来,如responseA.pipe(responseB)
Done
最开始的思路最开始没搞清楚怎么用POST请求下载且前端该怎样接收和处理,关键字node 前端下载搜到的绝大多数都是用GET链接下载,加上刚刚接触node没有很好理解流的概念,因此一根筋的想如何通过POST请求转换成GET请求下载,于是自作主张采用了笨办法,走上了一条差点没回来的路:
前端点击下载,发送post请求A给node
由node获取参数向Java端发送post请求B把文件先下载到node本地(Java返回的记为responseA)并用responseB返回前端文件地址和文件名
前端获取到responseB后拼接成get请求模拟a标签点击去下载node中的文件
下载完成后再将node端对应文件删除。
写到这里自己都忍不住想锤自己,给自己挖坑不说,这样来回请求下载,流量double,真的是败家。
涉及的知识点
在前端项目根目录下新建proxy.conf.json文件,配置接口转发
{ "/api": { "target" : "http://localhost:3000"//server端port } }
保存后,配置package.json文件里start命令如下,保存后重新运行就好
"start": "ng serve --proxy-config proxy.conf.json",
node如何发送get/post请求
stream、buffer的概念:文章一 文章二
前端GET下载的三种方式
直接将拼接好的GET请求url赋值给a标签,模拟点击
先获取数据流存进blob对象,a.href = window.URL.createObjectURL(blob)
每次调用createObjectUR的时候,一个新的URL对象就被创建了.即使你已经为同一个文件创建过一个URL. 如果你不再需要这个对象,要释放它,需要使用URL.revokeObjectURL()方法. 当页面被关闭,浏览器会自动释放它,但是为了最佳性能和内存使用,当确保不再用得到它的时候,就应该释放它.
新建一个隐藏的iframe,src设置为如上一步的url即可
前端如何接收文件流并下载
原生xhr请求写法
var xhr = new XMLHttpRequest(); xhr.open("get", url, true); xhr.responseType = "blob"; xhr.onload = function() { if (this.status == 200) { var blob = this.response; var img = document.createElement("img"); img.onload = function(e) { window.URL.revokeObjectURL(img.src); }; img.src = window.URL.createObjectURL(blob); $("#imgcontainer").html(img); } } xhr.send();
axios请求写法
axios.post("/api/download_reports",msgArr,{ responseType:"blob", onDownloadProgress (a){ //监听下载进度 if(a.lengthComputable){ let percent = (a.loaded*100/a.total).toFixed(2) console.log(percent) $("#percent").html(tempLoaded) } } }) .then(response => { console.log(response) if(response.status == 200){ const blob = new Blob([response.data],{type: "application/octet-stream"}); const url = window.URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; a.download = baseName+".zip"; document.body.appendChild(a); a.click(); document.body.removeChild(a); window.URL.revokeObjectURL(url); } }) .catch(error => { console.log(error) })
前端如何获取下载进度,并进一步完成进度条设置
axios.post("/喵",postData, { onUploadProgress (a){ //上传进度同理 console.log(a) }, onDownloadProgress (a){ //控制台输出后,可以发现我们能够通过a.loaded*100/a.total来获得下载进度 //但需注意的是如果node端的responseB没有设置"Content-Length"即二进制流size的话 //axios.post此时获取到的下载进度事件对象a里lengthComputable为false,进而a.total=0 //进而无法获取百分比进度 console.log(a) } })
前端POST下载的两种方式
这个没有什么好说的,唯一可能要注意的就是表单里input传参的时候,如果参数比较多,可以用JSON.stringify()转换,只向后端发送一个字符串就好
以上就是自己对node实现文件前端下载的一些理解,如有不妥欢迎交流指正~
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/100252.html
摘要:不管是还是,其实都是基于实现的。文件,看名字就知道它是的配置文件。接下来会向外暴露可以指定是环境还是环境。这个有点不一样的是他依赖一个的配置文件。注意这三个的顺序不能错,是从右往左执行的。到这里,一个小小的脚手架雏形其实就有了。不管是vue-cli还是react-sprite,其实都是基于webpack实现的。试想,如果没有脚手架,你自己能搭一个吗?看完这篇博客,让你明白webpak都有些什...
摘要:是负责展示京东商品的落地页面。比如京东首页,正常情况加载完页面一共有多个节点,基本上全部用于展示商品信息广告图和内容布局,页面上的三方异步服务也比较少。 原文:https://keelii.github.io/2016/07/31/something-have-to-say-with-JD-item 简介 详情页也叫做单品页,域名以「item.jd.com/skuid.html」为格式...
摘要:所以,现在的我是一个只会不会写的伪前端。技术升华环节如何理解你的微博简介一个只会写不会写的伪前端工程师你觉得和学习起来各有什么难点呢微博我好久没去碰了,其实现在应该是写一个连都不会写,更不会写的伪前端工程师。 showImg(https://segmentfault.com/img/bVT0Y4?w=900&h=385); 上周没和大家见面,是去邀请大佬来访谈了(///▽///)社区访...
摘要:那我们有没有办法不刷新页面又能看到代码的更新呢其实很简单,因为已经内置了这样的功能,我们只要配置下的注意到上面的代码,我们增加了,让开发环境有了热更新的能力。 作者:Nicolas (沪江Web前端)本文为原创文章,转载请注明作者及出处 本文的 webpack 代码示例根据 webpack 2.7.0 编写,并在 Mac 上正常运行。 去年一篇《在 2016 年学 JavaScript...
阅读 1906·2021-09-23 11:21
阅读 1692·2019-08-29 17:27
阅读 1052·2019-08-29 17:03
阅读 718·2019-08-29 15:07
阅读 1914·2019-08-29 11:13
阅读 2373·2019-08-26 12:14
阅读 903·2019-08-26 11:52
阅读 1728·2019-08-23 17:09