文件下载时前后台MD5校验
背景
在项目中发现,文件下载时有可能出现文件不完全导致的文件无法打开的情况,考虑在后台响应中加入文件MD5,与前台取得文件后生成的MD5值作一次校验,来判断文件是否正确下载。
问题
此功能的难点是如何在response中加入MD5值。原文件下载接口中使用的是HttpServletResponse,然后在前台使用a标签的点击事件来实现,在开发过程中,首先想到的是在response的headers中加入MD5信息,然后在前台想办法取到,即
... // response.setHeader("md5",md5sum(bytes)); ... private String md5sum(byte[] bytes){ ... }
在实际开发中发现,这个方法无法正常下载文件,所以应该通过其他途径来实现。(这种想法还是很天真的2333)
方案
之前的开发中有用到Blob对象,在前台中可以使用Blob对象来实现文件下载,即
... var url = window.URL.createObjectURL(blob); var a = document.createElement('a'); a.href = url; a.download = filename; a.click(); ...
那么肯定可以在后台接口中加上文件的bytearray,再在JS中使用var blob = new Blob([bytearray]);
来声明一个blob对象实现文件下载,那么也可以在返回的JSON中加入生成的MD5值了。
代码
后台
import org.apache.commons.io.IOUtils; import java.util.HashMap; import java.util.Map; import java.io.*; import java.security.MessageDigest; ... private final char HEX_DIGITS[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; ... @Override public Object downloadFile(String burketName, String fileName){ try { InputStream is = ...; byte[] byteArray = IOUtils.toByteArray(is); String fileMD5 = md5sum(byteArray); Map map = new HashMap(); map.put("file",byteArray); map.put("md5",fileMD5.toUpperCase()); if(is!=null){ is.close(); } return map; }catch (Exception ex){ ex.printStackTrace(); } return ""; } private String toHexString(byte[] b) { StringBuilder sb = new StringBuilder(b.length * 2); for (int i = 0; i < b.length; i++) { sb.append(HEX_DIGITS[(b[i] & 0xf0) >>> 4]); sb.append(HEX_DIGITS[b[i] & 0x0f]); } return sb.toString(); } private String md5sum(byte[] byteArray) { InputStream is = new ByteArrayInputStream(byteArray); byte[] buffer = new byte[1024]; int numRead = 0; MessageDigest md5; try{ md5 = MessageDigest.getInstance("MD5"); while((numRead=is.read(buffer)) > 0) { md5.update(buffer,0,numRead); } return toHexString(md5.digest()); } catch (Exception e) { System.out.println("parse md5 error"); return null; } } ...
前台
... // 前台在生成MD5时使用了SparkMD5插件 fetch(url, {headers:headers).then(function (res) { return res.json(); }).then(function (blob) { var spark = new SparkMD5.ArrayBuffer(); //这个是接口中返回的MD5 var serverMD5=blob.md5; var byteBuffer=_base64ToArrayBuffer(blob.file); spark.append(byteBuffer); var clientMD5 = spark.end().toUpperCase(); // 判断文件是否下载完全 if(serverMD5 === clientMD5){ var f = new Blob([byteBuffer]); var url = window.URL.createObjectURL(f); var a = document.createElement('a'); a.href = url; a.download =filename; a.click(); window.URL.revokeObjectURL(f); } else{ console.log("文件下载时出错,请重新下载"); } }); function _base64ToArrayBuffer (base64) { var binary_string = window.atob(base64); var len = binary_string.length; var bytes = new Uint8Array(len); for (var i=0;i<len;i++) { bytes[i] = binary_string.charCodeAt(i); } return bytes.buffer; }
总结
以上就是在开发文件下载校验时的思路和代码分享,开发的关键就是在文件下载接口返回值中加入后台计算的文件MD5,主要就是通过后台接口中返回文件的bytearray和用作校验的MD5值,前台接收到接口返回后生成一个MD5来与接口返回的MD5作校验,再在前台中使用返回的bytearray,通过Blob来实现文件下载。
如果你还有更好的方案,欢迎给我留言,不胜感激。
传送门
原文地址:https://segmentfault.com/a/1190000016510744
相关推荐
-
mybatis 缓存及encache Java基础
2019-8-23
-
Java 开发者得力助手,深入实践 Spring Boot Java基础
2020-5-30
-
MyBatis操作Oracle批量插入 ORA-00933: SQL 命令未正确结束 Java基础
2019-9-15
-
关于Http协议,你必须要知道的 Java基础
2018-12-9
-
二分搜索以及其扩展形式 Java基础
2019-3-24
-
通过代码实例说明如何化腐朽为优雅 Java基础
2019-5-13
-
浅谈java线程池实现 Java基础
2019-9-17
-
Java NIO之套接字通道 Java基础
2019-3-22
-
RecyclerView的Item的单击事件 Java基础
2020-5-30
-
spring-boot中使用spring-boot-devtools Java基础
2020-6-14