山东网站优化公司,wordpress strip tags,中文搜索引擎排行榜,长春火车站和高铁站是一个站吗文章目录 简介简单文件下载通过模拟form表单提交通过XMLHttpRequest方式 跨域(oss)下载并压缩文件完整示例文件压缩跨域设置 简介
相信各位开发朋友都遇到过下载的文件的需求#xff0c;有的非常简单#xff0c;基本链接的形式就可以。
有的就比较复杂#xff0c;涉及跨域… 文章目录 简介简单文件下载通过模拟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);
}上面这种方式
优点是简单缺点是错误不友好出错了没有提示信息
如果希望错误信息友好一点可以通过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();ResultVoid 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个不好处理的问题
跨域文件流压缩
解决方案
跨域问题主要是浏览器限制可以通过后端添加header Access-Control-Allow-Origin或者直接设置浏览器处理文件压缩可以使用jszip
完整示例
!DOCTYPE html
htmlheadmeta charsetutf-8title跨域下载/title/headbodybutton onclickdownload()下载/button/body
/html
script typetext/javascript srcjs/jszip.js/script
scriptfunction 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 nonea.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 nonea.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个
服务端返回response的header Access-Control-Allow-Origin值类似于*设置浏览器
设置服务器的方式很多以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中设置 设置这些的目的只有一个就是然response中有Access-Control-Allow-Origin 除了设置服务端还可以设置浏览器以Chrome为例 设置浏览器的启动参数
–disable-web-security --user-data-dirD:\ChromeDevData