大文件下载优化方案(nginx+Springboot+vue)---非常完美

1、背景:

系统中有个文件下载的功能,下载的文件从1k-几十G不等,小文件下载没有问题,只要上G了,下载大概率失败。基于以上现状,对技术方案记性优化。

2、历史方案:

2.1 服务器读取文件流传输+前端blob接收

描述:

  • 后端接口通过response的IO通道,读写文件流传输
  • 前端接收Blob数据,等所有接收完成,再保存成文件

优点:传统方案,方案固定好写

缺点:文件先读到内存再输出,存在服务器压力;大文件传输过程中客户端和服务器的连接管道容易断开:broken pieped;前端接收内存压力;进度需要自己记录和计算;

2.2 使用NIO读取写入(同上)

描述:传输速度比BIO能快10倍以内

优缺点同上;

2.3 分片下载

描述:前端和后端都使用分片下载,等前端把所有的分片下载完成再合并成一个文件;

优缺点同上;能减少连接断开的概率;

3、完美方案:

目标:有进度显示;能正常下载完成;多人下载无压力;

描述:

  1. 进度显示:前端使用window.location.href=下载文件连接  的形式;
  2. 后端接口改成GET接口,参数拼接在url后面,包括token:因为href是新启动一个请求,并且header不能自定义,所以接口的鉴权只能放在url后面;
  3. 后端接口对url参数和token进行验证;
  4. 开始后端接口逻辑:
  5. 获取文件路径,设置response的header属性,重定向到Nginx配置的内部文件路由
  6. nginx返回文件信息
  7. 浏览器接收并在下方显示下载进度

Nginx.conf配置

location /ngdownload {
            alias /opt/data;#文件目录的前缀
            internal;#标识内部接口
}

Java代码:

public void downloadByLink(HttpServletResponse response, String fileId) {
        //查询附件信息
        File file = getFile();//自己实现
        //鉴权实际已经通过gateway完成
        try {
            String fileName = URLEncoder.encode(file.getName(), "UTF-8");
            //Content-Disposition 表示文件的下载方式,attachment 表示文件需要下载,而不是在浏览器中打开
            response.addHeader("Content-Disposition", "attachment;filename=" + fileName);
            //设置URI给nginx进行内部的跳转/ngndownload
            response.setHeader("X-Accel-Redirect", "/ngndownload" + fileName ); 
            //限速 尽量不设置
            response.setHeader("X-Accel-Limit-Rate", "202400"); 
        } catch (UnsupportedEncodingException e) {
            log.error("文件下载失败 ", e);
            throw new BusinessException("文件下载失败");
        }
    }

你可能感兴趣的:(nginx,运维,spring,boot)