当前位置: 首页 > news >正文

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

相关文章:

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

文章目录 简介简单文件下载通过模拟form表单提交通过XMLHttpRequest方式 跨域(oss)下载并压缩文件完整示例文件压缩跨域设置 简介 相信各位开发朋友都遇到过下载的文件的需求&#xff0c;有的非常简单&#xff0c;基本链接的形式就可以。 有的就比较复杂&#xff0c;涉及跨域…...

Django 定义使用模型,并添加数据

教材&#xff1a; Python web企业级项目开发教程&#xff08;黑马程序员&#xff09;第三章 模型 实验步骤&#xff1a; 1.创建项目和应用 前置步骤可看前文&#xff0c;进入到指定文件位置后创建 django-admin startproject mysite python manage.py startapp app01 2.注册…...

联名物料常泄漏?一端叠满“安全buff”

前段时间&#xff0c;一则关于爆火影视剧与知名茶饮品牌联名的消息在社交平台上迅速传播&#xff0c;宣传物料的照片也随之曝光——门店尚未上新&#xff0c;“小道消息”便已被疯传。但这种情况并非首次发生&#xff0c;让众多网友不禁猜想&#xff1a;这究竟是一场精心策划的…...

Flutter UI组件库(JUI)

Flutter UI组件库 (JUI) 介绍 您是否正在寻找一种方法来简化Flutter开发过程&#xff0c;并创建美观、一致的用户界面&#xff1f;您的搜索到此为止&#xff01;我们的Flutter UI组件库&#xff08;JUI&#xff09;提供了广泛的预构建、可自定义组件&#xff0c;帮助您快速构建…...

国外电商系统开发-运维系统远程文件

设计初衷是为了让所有人都能方便的打开网页&#xff0c;就能查看Linux系统文件内容&#xff0c;而不再用cat、vim、more等命令去打开文件&#xff0c;这对于我们一个普通的研发或者是财务人员来说&#xff0c;显得太繁琐&#xff0c;因为他们很可能不会这些命令&#xff0c;其次…...

4. Node.js Path模块

2.3Path模块 2.3.1获取js文件的绝对路径 console.log(__dirname) //js文件所在的文件夹的绝对路径 console.log(__filename) //js文件的绝对路径输出&#xff1a; G:\py_project\nodejs_study G:\py_project\nodejs_study\file.js2.3.2拼接规范的绝对路径path.r…...

重构长方法之分解条件表达式

分解条件表达式 是一种重构长方法中常用的技术&#xff0c;它适用于复杂的条件逻辑。在方法中&#xff0c;条件分支&#xff08;if-else 或 switch&#xff09;有时会变得条件非常多&#xff0c;非常复杂&#xff0c;难以理解和维护。通过分解条件逻辑&#xff0c;可以让代码更…...

蚁群算法养老服务人员智能调度系统

养老行业近年来越发热门&#xff0c;如何有效调配服务人员成为许多机构的痛点。我们结合智能算法技术&#xff0c;开发出了一款专为养老行业量身打造的“蚁群算法养老服务人员调度系统”&#xff0c;能够精准、高效地为机构分配人员&#xff0c;从此告别人力资源调度难题。 系…...

java使用 IDEA自动补全功能 AI 插件

国内插件&#xff1a; CodeGeeX&#xff1a; 功能特性&#xff1a; 由国内团队开发&#xff0c;是一款智能编程助手插件。它集成了多种人工智能技术&#xff0c;能够在多个编程语言中提供智能代码补全、代码生成、代码优化和注释生成等功能。该插件特别适用于常见的编程任务…...

【ShuQiHere】 AI与自我意识:能否创造真正的自觉机器人?

&#x1f916;【ShuQiHere】 &#x1f4dc; 目录 引言人类意识的探索机器意识的五大理论 功能主义&#xff08;Functionalism&#xff09;信息整合&#xff08;Information Integration&#xff09;体现主义&#xff08;Embodiment&#xff09;行动主义&#xff08;Enaction&…...

【Linux 从基础到进阶】CPU性能调优与监控

CPU性能调优与监控 1. 引言 在计算机系统中&#xff0c;CPU是核心组件之一&#xff0c;其性能直接影响系统的整体表现和响应速度。无论是在企业服务器环境、虚拟化环境&#xff0c;还是大数据计算场景&#xff0c;优化和监控CPU性能都至关重要。通过合理的调优策略和监控工具…...

Centos基线自动化检查脚本

此脚本是一个用于检查Linux系统安全配置的Bash脚本。它通过多项安全标准对系统进行评估&#xff0c;主要检查以下内容&#xff1a; IP地址获取&#xff1a;脚本首先获取主机的IP地址&#xff0c;确保其以10.115开头。 密码策略检查&#xff1a; 检查最小密码长度&#xff08;P…...

OpenCV答题卡识别

文章目录 一、基本流程二、代码实现1.定义函数2.图像预处理&#xff08;1&#xff09;高斯模糊、边缘检测&#xff08;2&#xff09;轮廓检测&#xff08;3&#xff09;透视变换&#xff08;4&#xff09;阈值处理和轮廓检测 3.筛选和排序选项轮廓4.判断答案5.显示结果 三、总结…...

通用数据库对象设计

1. 公共属性 这里的数据模型以陈品山的实体-关系模型为基础&#xff0c;增加了两点修改。一是用“组”的概念表达实体间关系&#xff0c;并将组作为一种特殊实体。二是采用继承的思想&#xff0c;将实体的公共属性提取出来&#xff0c;放到统一表中。实体的特有属性保存在单独…...

Java基础12-特殊文件和日志技术

十二、特殊文件和日志技术 1、特殊文件 properties&#xff1a;用来存储键值对数据。 xml&#xff1a;用来存储有关系的数据。 1.1 properties文件 特点&#xff1a;存储键值对&#xff0c;键不能重复&#xff0c;文件后缀一般是.properties结尾的。 properties&#xff1a;是…...

2.4 STM32启动过程

目录 一,启动Flow 1.1 初始化MSP 1.2 初始化PC 1.3 设置堆栈大小 1.4初始化中断向量表 1.5 调用初始化函数(可选) 1.6 调用__main 二,Reset_Handler函数 一,启动Flow 下面是stm32在内部FLASH启动的启动建议流程图,在stm32复位到执行我们程序的main函数的过程中,…...

rm: cannot remove: Device or resource busy 解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…...

2024年的5款AI写作工具,你用过几个?

AI技术正逐渐渗透到我们生活的方方面面&#xff0c;其中就包括写作领域。今天&#xff0c;我要为大家介绍5款实用的AI写作助手&#xff0c;它们将帮助你提高写作效率&#xff0c;激发创作灵感&#xff0c;让你的写作之路更加顺畅。 1. 宙语Cosmos-全能写作助手 网址&#xff…...

泛癌热门靶点TROP2及研究工具试剂

前 言 TROP2属于肿瘤相关抗原之一&#xff0c;在多种肿瘤中表达升高&#xff0c;促进肿瘤细胞生长、增殖和转移。TROP2已经成为近年来NEJM、肿瘤学期刊、药物研发的多重热点。通过PubMed检索到477篇相关文献&#xff0c;自2020年文献数量逐步增加&#xff0c;2022年达81篇&am…...

2848. 与车相交的点

2848. 与车相交的点 题目链接&#xff1a;2848. 与车相交的点 代码如下&#xff1a; class Solution { public:int numberOfPoints(vector<vector<int>>& nums){set<int> s;for (int i 0; i < nums.size(); i){for (int j nums[i][0]; j < nu…...

Java 8 Stream API 入门到实践详解

一、告别 for 循环&#xff01; 传统痛点&#xff1a; Java 8 之前&#xff0c;集合操作离不开冗长的 for 循环和匿名类。例如&#xff0c;过滤列表中的偶数&#xff1a; List<Integer> list Arrays.asList(1, 2, 3, 4, 5); List<Integer> evens new ArrayList…...

STM32F4基本定时器使用和原理详解

STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...

vue3 字体颜色设置的多种方式

在Vue 3中设置字体颜色可以通过多种方式实现&#xff0c;这取决于你是想在组件内部直接设置&#xff0c;还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法&#xff1a; 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...

对WWDC 2025 Keynote 内容的预测

借助我们以往对苹果公司发展路径的深入研究经验&#xff0c;以及大语言模型的分析能力&#xff0c;我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际&#xff0c;我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测&#xff0c;聊作存档。等到明…...

跨链模式:多链互操作架构与性能扩展方案

跨链模式&#xff1a;多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈&#xff1a;模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展&#xff08;H2Cross架构&#xff09;&#xff1a; 适配层&#xf…...

CocosCreator 之 JavaScript/TypeScript和Java的相互交互

引擎版本&#xff1a; 3.8.1 语言&#xff1a; JavaScript/TypeScript、C、Java 环境&#xff1a;Window 参考&#xff1a;Java原生反射机制 您好&#xff0c;我是鹤九日&#xff01; 回顾 在上篇文章中&#xff1a;CocosCreator Android项目接入UnityAds 广告SDK。 我们简单讲…...

大模型多显卡多服务器并行计算方法与实践指南

一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...

NLP学习路线图(二十三):长短期记忆网络(LSTM)

在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...

企业如何增强终端安全?

在数字化转型加速的今天&#xff0c;企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机&#xff0c;到工厂里的物联网设备、智能传感器&#xff0c;这些终端构成了企业与外部世界连接的 “神经末梢”。然而&#xff0c;随着远程办公的常态化和设备接入的爆炸式…...

基于Java+VUE+MariaDB实现(Web)仿小米商城

仿小米商城 环境安装 nodejs maven JDK11 运行 mvn clean install -DskipTestscd adminmvn spring-boot:runcd ../webmvn spring-boot:runcd ../xiaomi-store-admin-vuenpm installnpm run servecd ../xiaomi-store-vuenpm installnpm run serve 注意&#xff1a;运行前…...