文件下载时前后台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来实现文件下载。

如果你还有更好的方案,欢迎给我留言,不胜感激。

传送门

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值