当前位置: 首页 > 后端技术 > Node.js

node实现文件下载不得不说的那些事

时间:2023-04-03 14:54:39 Node.js

这几天一直在做远程文件下载,现在终于解决了。我想记录下我踩过的陷阱,记录下我想要击败自己的心。应用场景是这样,底层的逻辑数据请求接口是用Java写的,也就是说原始文件存在于Java服务器上,返回时有加密措施。由于工作需要,前端数据采集操作需要节点服务器做中间转发。Java接口使用post方式请求下载前端点击下载,浏览器启用内置下载器进行下载,可以看到如下图的进度。在下载多个文件的场景下(比如本例中node作为文件服务器,可以直接和前端交互),完全可以通过串接GET请求url来模拟点击下载。系统开销还是很小的,响应也很快。如果您在本示例的场景中遇到此类问题,请参阅链接了解详细信息。当请求参数过长或者为了安全,需要使用POST下载。前端最终采用的方案是通过模拟表单提交POST请求。节点端通过管道连接responseA和responseB,如responseA.pipe(responseB)完成。处理,关键字node前端下载,搜索大部分都是用GET链接下载,刚接触node的时候对streams的概念不是很了解,所以只想着怎么把POST请求转成GET请求下载,于是自评采用了笨办法,走上了一条几乎一去不复返的路:前端点击下载,发送post请求A给node,node获取参数后发送post请求B给Java端下载先将文件传到节点本地(JavaResponseA返回的记录),用responseB返回前端文件地址和文件名。前端拿到responseB后,拼接成get请求,模拟一个标签,点击下载节点中的文件。下载完成后,删除节点端对应的文件。写到这里忍不住想锤自己,给自己挖个坑,不说了,就这样来回求下载,流量翻倍,真是败家子。涉及知识点Angular前端访问节点跨域设置在前端项目根目录新建proxy.conf.json文件,配置接口转发{"/api":{"target":"http://localhost:3000"//保存服务器端端口后}},在package.json文件中配置启动命令如下,保存再运行即可"start":"ngserve--proxy-configproxy.conf.json”,node如何发送get/post请求stream和buffer的概念:第1条第2条前端GET下载的三种方式,直接将拼接好的GET请求url赋给a标签,模拟点击首先获取数据流存储在blob对象中,a.href=window.URL.createObjectURL(blob)每次调用createObjectUR都会创建一个新的URL对象。即使您已经为同一个文件创建了一个URL。如果你不再需要这个对象,要释放它,使用URL.revokeObjectURL()方法。当页面关闭时,浏览器会自动释放它,但为了最佳性能和内存使用,应该在不再需要时释放它。新建一个隐藏的iframe,设置src为上一步的url,就是前端接收文件流下载原生xhr请求的方式。varxhr=newXMLHttpRequest();xhr.open("get",url,true);xhr.responseType="blob";xhr.onload=function(){if(this.status==200){varblob=this.response;varimg=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){letpercent=(a.loaded*100/a.total).toFixed(2)console.log(percent)$('#percent').html(tempLoaded)}}}).then(response=>{console.log(response)if(response.status==200){constblob=newBlob([response.data],{type:'application/octet-stream'});consturl=window.URL.createObjectURL(blob);consta=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)})Frontend如何获取下载进度并进一步完成进度条设置axios.post('/喵',postData,{onUploadProgress(a){//上传进度和conso一样le.log(a)},onDownloadProgress(a){//控制台输出后,我们发现可以通过a.loaded*100/a.total获取下载进度//但是需要注意的是,如果node端的responseB如果设置了'Content-Length',即此时axios.post获取的下载进度事件对象a中的二进制流//lengthComputable的大小为false,然后a。total=0//获取不到百分比进度console.log(a)}})前端POST下载的两种方式没什么好说的。唯一需要注意的是,在表单中input传递参数的时候,如果参数比较多,可以使用JSON.stringify()进行转换,只向后端发送一个字符串即可。以上是我对node实现文件前端下载的理解。如有不妥之处,欢迎交流指正~