JavaScript下载文件(简单模式、跨域问题、文件压缩)

文章目录

  • 简介
  • 简单文件下载
    • 通过模拟form表单提交
    • 通过XMLHttpRequest方式
  • 跨域(oss)下载并压缩文件
    • 完整示例
    • 文件压缩
    • 跨域设置

简介

相信各位开发朋友都遇到过下载的文件的需求,有的非常简单,基本链接的形式就可以。

有的就比较复杂,涉及跨域和压缩文件,例如,文件在OSS中,有的oss不支持压缩文件,要下10个文件就得弹10个下载出来。

业务老师多半是没有办法接受这种情况,怎么处理呢?

这就涉及到跨域获取文件并压缩文件了。

本文会介绍一下简单下载和下载OSS文件并压缩。

简单文件下载

首先我们看一些2种简单下载方式

通过模拟form表单提交

function downloadRemoteFile(url,materialId) {var body = document.getElementsByTagName('body')[0];var form = document.createElement('form');form.method = 'POST';form.action = url;var param = document.createElement('input');param.type = "hidden";param.name = "materialId";param.value = materialId;form.appendChild(param);body.appendChild(form);form.submit();body.removeChild(form);
}

上面这种方式:

  1. 优点是简单
  2. 缺点是错误不友好,出错了,没有提示信息

如果希望错误信息友好一点,可以通过XMLHttpRequest方式。

通过XMLHttpRequest方式

function downloadRemoteFileXMLHttpRequest(url,materialId) {console.log("${downloadUrl}" + " " + materialId);var xhr = new XMLHttpRequest();xhr.open("POST", url, true);xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded")xhr.onload = function () {if (xhr.status === 200) {if (xhr.response == null || xhr.response == "" || xhr.response == undefined) {alert("下载文件出错,请检查文件是否存在:" + materialId);return;}// 获取判断Content-Type// var contentType = xhr.getResponseHeader("Content-Type");var blob = new Blob([xhr.response], { type: "application/octet-stream" });var fileName = getFileNameFromResponseHeader(xhr);var link = document.createElement("a");link.href = window.URL.createObjectURL(blob);link.download = fileName;link.click();link.remove();window.URL.revokeObjectURL(link.href);} else {alert("下载响应异常");console.log(xhr);}};xhr.send("materialId=" + materialId);
}function getFileNameFromResponseHeader(xhr) {var contentDisposition = xhr.getResponseHeader("content-disposition")var matchResult = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/.exec(contentDisposition);if (matchResult != null && matchResult[1]) {return decodeURIComponent(matchResult[1].replace(/['"]/g, ""));}return "default-name";
}

通过XMLHttpRequest方式就灵活很多,虽然还是模拟了a链接,但是能先处理响应。

例如,下载后端可以能有一些预检查,如果预检查都没有通过,那么可能返回的就不是Blob文件,而是一个json。

通过XMLHttpRequest方式就可以通过判断ContentType内容,来获取文件流、或是json的内容,从而把错误信息比较友好的展示给用户。

对于后端下载接口,可能更好的方式是把信息写到header中,这样对于前端来说就能更好统一处理逻辑。

response.addHeader("success", "false");
response.addHeader("message", URLEncoder.encode("该数据您无权下载", StandardCharsets.UTF_8));

后端不同处理方式(仅仅演示,实际操作最后统一逻辑):

@RequestMapping("/download")
public void download(HttpServletResponse response, @RequestParam("fid") Long fid) throws IOException {if (fid < 0) {response.setContentType("application/json");PrintWriter writer = response.getWriter();Result<Void> result = ResultHelper.getFailResult("文件不存在");writer.write(JSON.toJSONString(result));return;}if (fid < 100) {response.addHeader("success", "false");String message = "该数据您无权下载";response.addHeader("message", URLEncoder.encode(message, StandardCharsets.UTF_8));return;}try (FileInputStream fis = new FileInputStream("F:\\tmp\\季报统计表.xlsx");OutputStream os = response.getOutputStream()) {String fileName = URLEncoder.encode("季报统计表.xlsx",StandardCharsets.UTF_8);response.reset();response.setContentType("application/octet-stream");response.setHeader("Content-Disposition", "attachment;filename=" + fileName);response.addHeader("success", "true");IOUtils.copy(fis, os);}
}

跨域(oss)下载并压缩文件

下载并压缩文件主要有2个不好处理的问题:

  1. 跨域
  2. 文件流压缩

解决方案:

  1. 跨域问题主要是浏览器限制,可以通过后端添加header Access-Control-Allow-Origin或者直接设置浏览器处理
  2. 文件压缩可以使用jszip

完整示例

<!DOCTYPE html>
<html><head><meta charset="utf-8"><title>跨域下载</title></head><body><button onclick="download()">下载</button></body>
</html>
<script type="text/javascript" src="js/jszip.js"></script>
<script>function fetchFile(url, zip) {window.fetch(url, {method: "GET",// mode: 'no-cors',mode: 'cors' // 允许跨越}).then(response => {// no-cors 这里不执行return response.blob();}).catch(error => {console.log(error);});}// 下载文件function downloadFile(url, fileName) {const a = document.createElement('a')a.style.display = 'none'a.href = urla.download = fileNamedocument.body.appendChild(a)a.click()document.body.removeChild(a)}function download() {const zip = new JSZip();// 从远程服务器获取文件const urls = ['http://127.0.0.1:8087/file/download2'];let map = new Map();let promises = [];var index = 0;urls.forEach(function(value, index, array) {// cors 表示可以跨越,服务端必须设置Access-Control-Allow-Origin//no-cors fetch不会执行then,拿不到文件var result = fetch(value, {mode: 'cors'}).then(response => response.blob());promises.push(result);map.set(index++, value);});Promise.all(promises).then(results => {var flag = true;if (results.every(result => result !== undefined)) {flag = true;} else {flag = flase;}if(flag){index = 0;results.forEach(blob => {// promise 结果是按顺序返回的var url = map.get(index++);var filename = getFileName(url);zip.file(filename, blob, {binary: true});});zip.generateAsync({type: "blob"}).then(function(content) {const url = window.URL.createObjectURL(content);downloadFile(url, "result.zip");});}else{alert("有文件下载失败请重试!");}}).catch(error => console.error('Error:', error));}function getFileName(url) {var url = url.substring(url.lastIndexOf("/") + 1);var idx = url.lastIndexOf("?");if (idx > 0) {url = url.substring(0, idx);}return decodeURI(url);}
</script>

文件压缩

首先下载jszip的最新版本,注意使用新版本(3.10.x)和老版本的api差别较大。

jszip下载

function zip() {const zip = new JSZip();// 添加一个文本文件zip.file("Hello.txt", "Hello World\n");// 添加一个json文件let jsonData = {};const blob = new Blob([JSON.stringify(jsonData, null, 4)], {type: 'application/json'});zip.file('notes.json', blob);// 添加文件夹const folder = zip.folder("subdir");// 在文本文件中添加一个文本文件folder.file("Hi.txt", "Hi\n");// 除了blob类型,还可以设置为base64zip.generateAsync({type: "blob"}).then(function(content) {const url = window.URL.createObjectURL(content);downloadFile(url, "result.zip");});
}// 下载文件
function downloadFile(url, fileName) {const a = document.createElement('a')a.style.display = 'none'a.href = urla.download = fileNamedocument.body.appendChild(a)a.click()document.body.removeChild(a)
}

跨域设置

如果你看到一个类似于下面的错误,那是因为浏览器限制,不允许跨域。

跨域错误

Access to fetch at ‘http://127.0.0.1:8087/file/download2’ from origin ‘http://127.0.0.1:8848’ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource. If an opaque response serves your needs, set the request’s mode to ‘no-cors’ to fetch the resource with CORS disabled.

解决这个问题的方法有2个:

  1. 服务端返回response的header Access-Control-Allow-Origin值类似于*
  2. 设置浏览器

设置服务器的方式很多,以springboot为例:

可以通过设置Filter:

import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;import java.io.IOException;@Component
public class CorsFilter implements Filter {@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {HttpServletResponse res = (HttpServletResponse) response;res.setHeader("Access-Control-Allow-Origin", "*");res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
//        res.setHeader("Access-Control-Allow-Headers", "Authorization");res.setHeader("Access-Control-Allow-Headers", "*");chain.doFilter(request, response);}
}

可以设置WebMvcConfigurer:

package vip.meet.config;import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class CorsConfig implements WebMvcConfigurer {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**").allowedOrigins("*").allowedMethods("GET", "POST", "PUT", "DELETE").allowCredentials(true).allowedHeaders("*");}
}

可以直接在单个请求中设置:response.setHeader(“Access-Control-Allow-Origin”, “*”);

OSS中设置:

oss跨域设置

设置这些的目的只有一个就是然response中有Access-Control-Allow-Origin

response Access-Control-Allow-Origin

除了设置服务端,还可以设置浏览器,以Chrome为例:

浏览器跨域设置

设置浏览器的启动参数:

–disable-web-security --user-data-dir=D:\ChromeDevData

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/55825.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【顶刊核心变量】中国地级市绿色金融试点改革试验区名单数据(2010-2023年)

一、测算方式&#xff1a; 参考《中国工业经济》崔惠玉&#xff08;2023&#xff09;老师的研究&#xff0c;2017 年&#xff0c;国务院决定将浙江、广东、江西、贵州和新疆的部分地区作为绿色金融改革创新试验 区的首批试点地区。试点地区在顶层设计、组织体系、产品创新、配…

Biomamba求职| 国奖+4篇一作SCI

转眼间我也要参加秋招啦&#xff0c;认真的求职帖&#xff0c;各位老师/老板欢迎联系~其它需要求职的小伙伴也欢迎把简历发给我们&#xff0c;大家一起找工作。 一、基本信息 姓名&#xff1a;Biomamba 性别&#xff1a;男 出厂年份&#xff1a;1998 籍贯&#xff1a;浙江…

flutter升级,从3.10.6升级到3.16.9 混编项目iOS跑不起来

flutter升级&#xff0c;从3.10.6升级到3.16.9&#xff0c;如果直接去终端用命令行flutter upgrade v3.16.9很难保证不进入 dev分支升级成beta版本。 所以采取了 https://docs.flutter.dev/release/archive 点击这里去进行升级&#xff0c;这个时候也不要直接替换&#xff0c…

Visual Studio 2022安装(含重生版)

前言&#xff1a; 昨天调试代码的时候发现程序怎么都运行不了&#xff0c;错误显示无法找到文件啊啊啊&#xff0c;能力有限&#xff0c;找不出错误源&#xff0c;然后就狠心删掉所有相关文件来“重新开始”&#xff01; 正文&#xff1a; 1.官网下载&#xff08;内定中文版…

GS-SLAM论文阅读笔记-CG-SLAM

前言 这是一篇不是最新的工作&#xff0c;我之前没有阅读&#xff0c;但是我前几天阅读GLC-SLAM的时候&#xff0c;发现它的一部分内容参考了CG-SLAM&#xff0c;并且CG-SLAM最近被ECCV2024接收&#xff0c;说明这是一片值得参考的好文章&#xff0c;接下来就阅读一下吧&#…

QUUID 使用详解

UUID 通常由 128 位&#xff08;16 字节&#xff09;组成&#xff0c;通常表示为 32 个十六进制数字&#xff0c;分为五个部分&#xff0c;格式如下&#xff1a; QUuid 是 Qt 框架中用于生成和处理 UUID&#xff08;通用唯一标识符&#xff09;的类。UUID 是一种标准的标识符格…

sklearn机器学习实战——随机森林回归与特征重要性分析全过程(附完整代码和结果图)

sklearn机器学习实战——随机森林回归与特征重要性分析全过程&#xff08;附完整代码和结果图&#xff09; 关于作者 作者&#xff1a;小白熊 作者简介&#xff1a;精通python、matlab、c#语言&#xff0c;擅长机器学习&#xff0c;深度学习&#xff0c;机器视觉&#xff0c;目…

知识图谱入门——7:阶段案例:使用 Protégé、Jupyter Notebook 中的 spaCy 和 Neo4j Desktop 搭建知识图谱

在 Windows 环境中结合使用 Protg、Jupyter Notebook 中的 spaCy 和 Neo4j Desktop&#xff0c;可以高效地实现从自然语言处理&#xff08;NLP&#xff09;到知识图谱构建的全过程。本案例将详细论述环境配置、步骤实现以及一些扩展和不足之处。 源文件已上传我的资源区。 文章…

【VScode】如何使用详细步骤【笔记】、配置 C / C ++【笔记】

2024 - 10 - 10 - 笔记 - 24 作者(Author)&#xff1a;郑龙浩(仟濹) 该笔记写于 2024-07-02 摘抄到博客上的时间是 2024-10-10 VScode配置 C / C 笔记 我是看了下方链接的视频后为了方便后期复习做的笔记: B站某UP主的视频如下&#xff1a; VScode配置C/C开发环境&#xff…

VMware桥接模式无法连接网络

windows下打开控制面板&#xff0c;找到WLAN&#xff0c;记住下面的名称&#xff08;带有VMware的都是虚拟机的网卡&#xff0c;要找到物理主机的网卡&#xff09; 回到VMware&#xff0c;编辑——打开虚拟网络编辑器 桥接选择上面的WLAN下的网络名称&#xff0c;确定即可。&…

需求9——通过一个小需求来体会service层的作用

昨天在完成了睿哥的需求验收之后&#xff0c;暂时没有其他任务&#xff0c;因此今天可能会比较有空闲时间。趁着这个机会&#xff0c;我打算把之前完成的一些需求进行总结&#xff0c;方便以后复习和参考。 在8月份的时候&#xff0c;我负责了一个需求&#xff0c;该需求的具体…

基于xml配置文件的Spring事务

在项目中对事务属性通常传播属性&#xff0c;回滚属性&#xff0c;隔离级别&#xff0c;超时属性都取默认值&#xff0c;只有只读属性会如下的配置&#xff1a; 什么意思&#xff1a;Service层你的类里的方法&#xff0c;以get&#xff0c;find&#xff0c;select等开头的方法是…

Robust多模态模型的开发

本文所涉及所有资源均在 传知代码平台 可获取。 目录 Robust 多模态模型&#xff1a;寻找遗失的模态&#xff01; 一、研究背景 二、模型结构和代码 三、数据集介绍 六、性能展示 六、实现过程 七、运行过程 Robust 多模态模型&#xff1a;寻找遗失的模态&#xff01; 近年来&a…

threejs-基础材质设置

一、介绍 主要内容&#xff1a;基础材质(贴图、高光、透明、环境、光照、环境遮蔽贴图) 主要属性&#xff1a; side: three.DoubleSide, //设置双面 color: 0xffffff, //颜色 map: texture, //纹理 transparent: true, // 透明度 aoMap: aoTexture, //ao贴图 aoMapIntensity: 1…

Linux下载安装MySQL8.4

这里写目录标题 一、准备工作查看系统环境查看系统架构卸载已安装的版本 二、下载MySQL安装包官网地址 三、安装过程上传到服务器目录解压缩&#xff0c;设置目录及权限配置my.cnf文件初始化数据库配置MySQL开放端口 一、准备工作 查看系统环境 确认Linux系统的版本和架构&am…

【js逆向学习】极志愿 javascript+python+rpc

JSRPC使用方式 逆向目标逆向过程逆向分析1、什么是 websocket2、websocket的原理3、总体过程3.1 环境说明3.2 python服务端代码3.3 python客户端代码 4、Sekiro-RPC4.1 执行方式4.2 客户端环境4.3 参数说明4.4 SK API4.5 python代码调试4.6 代码注入流程 逆向总结 逆向目标 网…

AI资深导师指导-ChatGPT深度科研工作应用、论文撰写、数据分析及机器学习与AI绘图

2022年11月30日&#xff0c;可能将成为一个改变人类历史的日子——美国人工智能开发机构OpenAI推出了聊天机器人ChatGPT3.5&#xff0c;将人工智能的发展推向了一个新的高度。2023年4月&#xff0c;更强版本的ChatGPT4.0上线&#xff0c;文本、语音、图像等多模态交互方式使其在…

太速科技-607-基于FMC的12收和12发的光纤子卡

基于FMC的12收和12发的光纤子卡 一、板卡概述 本卡是一个FPGA夹层卡&#xff08;FMC&#xff09;模块&#xff0c;可提供高达2个CXP模块接口&#xff0c;提供12路收&#xff0c;12路发的光纤通道。每个通道支持10Gbps,通过Aurora协议&#xff0c;可以组成X4&#xff0…

LivePortrait:创新的肖像动画技术与深度伪造的预防措施

文章链接&#xff1a;https://arxiv.org/pdf/2407.03168 代码仓库&#xff1a;https://liveportrait.github.io 在数字媒体和娱乐领域&#xff0c;将静态肖像照片转换成动态视频是一个引人入胜的话题。最近&#xff0c;由快手科技的研究团队发表在arXiv上的一篇论文介绍了一种…

有千元以内的高性价比自动猫砂盆吗?双十一必看选购攻略!

对于经常外出的铲屎官来说&#xff0c;自动猫砂盆真的是一个必需品&#xff0c;不仅仅是上班出差&#xff0c;节假日旅游出行&#xff0c;小到外出逛街&#xff0c;大到五六天&#xff0c;自动猫砂盆都能完美解决猫屎残留在猫砂盆里无人照料的问题&#xff0c;毕竟猫屎放久了&a…