前言

业务场景:当我点击一个按钮时,调用第三方接口,后台返回一个字节流,然后浏览器弹出文件另存为的弹窗,直接保存。
但是在实际操作当中,浏览器拿到返回的字节流是不能解析的,下载的文件也是一个乱码文件,所以我决定在前端对返回的文件进行解析完成下载。但是是这样做有个问题,后面会解释

前端解析字节流下载文件

经过我多方查询资料,发现大部分都是使用xhr,因为后台传回来的是字节流,所以不能用ajax方法(dataType没有能接受字节流的参数),要用原生的XMLHttpRequest。
前端代码如下所示

var xhr = new XMLHttpRequest();
var fileName = "文件名";//设置下载时候的文件名
//要请求的Url和携带的参数
var url = "";
xhr.open("get", url, true);//打开请求
//设置响应类型为blob类型(接受字节流)
xhr.responseType = "blob";
xhr.onload = function () {//返回成功之后执行的方法
if (this.status == "200") {

--------下载的部分开始-----
	//获取响应文件流  
	var blob = this.response;
    //将文件流保存到a标签
    self.$(".targetLi a").attr("href", window.URL.createObjectURL(blob));
    self.$(".targetLi a").attr("download",fileName);
    self.$(".targetLi a span").click();
    $("a").remove();   
--------下载的部分结束-----

} else if (this.status == "500"){
    //链接响应失败
}}
xhr.send();//发送请求

下载部分
(1)用window.URL.createObjectURL(blob)方法讲后台返回的字节流转换成URL,然后在页面上创建一个不可见的a标签(display:none)。a标签里面嵌多一层span元素,用于触发点击事件(等下告知为什么)。将转化好的URL赋值给a标签的href属性。ps:如果你创建的a标签外面的父元素有点击事件,要记得给a标签加上阻止冒泡[event.stopPropagation(); ]。

(2)最后通过.click();方法触发a标签的点击。但是我之前尝试过直接调用a标签.click();来触发点击事件,但是没有触发到,后来通过点击a标签里面span,通过事件冒泡的方式来触发a标签的点击事件$(“a span”).click();

(3)结束完以上操作后,用remove()方法,把a标签移除掉。

(4)保存文件的弹窗的出现。

当我们点击下载按钮时,问题出现了,跨域。所以我改变思路,在后端处理返回的字节流,直接返回response

Java向回调的url推送数据 java调用接口返回的文件流_Java向回调的url推送数据

后端处理返回字节流,完成下载

public HttpServletResponse downloadForString(HttpServletResponse response,String fileId,String type) {

        String fileName = SysTools.getGUID()+"文件."+type;
        //String context = HttpUtil.get(download+fileId);
        byte[] buffer = HttpUtil.downloadBytes("url"+ fileId);
        try {

            //byte[] buffer = new String(context).getBytes();
            // 清空response
            response.reset();
            // 设置response的Header
            response.addHeader("Content-Disposition", "attachment;filename=" + new String(fileName.getBytes("utf-8"),"ISO8859-1"));
            response.addHeader("Content-Length", "" + buffer.length);
            OutputStream toClient = new BufferedOutputStream(response.getOutputStream());
            response.setContentType("application/octet-stream");
            toClient.write(buffer);
            toClient.flush();
            toClient.close();
        } catch (IOException ex) {
            System.out.println(ex.getMessage());
        }
        return response;
    }

至此完成下载