springboot X-Accel-Redirect 大文件下载实现

 更新时间:2023年06月09日 11:50:14   作者:Mr-Wanter  
本文主要介绍了springboot X-Accel-Redirect 大文件下载实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

前言

文件下载的方式:

  • nginx代理附件路径,直接访问。无法控制用户的权限。
  • 服务端流式读取文件内容。这个过程需要后端进程将文件读取到内存中然后再发给用户,会造成很大的资源开销。如果你文件较大,可能会超时,并且会占用比较大的内存,当用户下载量很大时有可能造成程序的崩溃。
  • 服务端权限控制后通过X-Accel-Redirect 重定向到nginx代理地址。传输快、服务器IO低,但是无法跟踪下载进度。

一、什么是 X-Sendfile?

X-Sendfile是一种将文件下载请求由后端应用转交给前端web服务器处理的机制,它可以消除后端程序既要读文件又要处理发送的压力,从而显著提高服务器效率,特别是处理大文件下载的情形下。

X-Sendfile 通过一个特定的 header 来实现:在 X-Sendfile 头中指定一个文件的地址来通告前端 web 服务器。当 web 服务器检测到后端发送的这个 header 后,它将忽略后端的其他输出,而使用自身的组件(包括 缓存头 和 断点重连 等优化)机制将文件发送给用户。

不过,在使用 X-Sendfile 之前,我们必须明白这并不是一个标准特性,在默认情况下它是被大多数 web 服务器禁用的。而不同的 web 服务器的实现也不一样,包括规定了不同的 X-Sendfile 头格式。如果配置失当,用户可能下载到 0 字节的文件。

nginx: X-Accel-Redirect

squid: X-Accelerator-Vary

apache: X-Sendfile

lighttpd: X-Sendfile/X-LIGHTTPD-send-file

使用X-Sendfile的缺点是你失去对文件传输机制的控制,后台不知道文件是否下载成功。

Nginx 默认支持该特性 ,不需要加载额外的模块。只是实现有些不同, 需要发送的 HTTP 头为 X-Accel-Redirect。

X-Accel-Redirect:
这个功能允许你在后端处理权限,日志或任何你想干的,Nginx提供内容服务给终端用户从重定向后的路径,因此可以释放后端去处理其他请求(直接由Nginx提供IO,而不是后端服务)。这个功能类似X-Sendfile 。

二、相关请求头说明

X-Accel-Limit-Rate
限制下载速度,单位字节。默认不限速度。

X-Accel-Buffering
设置此连接的代理缓存,将此设置为no将允许适用于Comet和HTTP流式应用程序的无缓冲响应。将>此设置为yes将允许响应被缓存。默认yes。

X-Accel-Expires
如果已传输过的文件被缓存下载,设置Nginx文件缓存过期时间,单位秒。默认不过期。

X-Accel-Charset
设置文件字符集,默认UTF-8

三、实现步骤

前置条件:

需要前端请求的Referer 和 nginx 在同一台机器,或者nginx代理到最终附件服务器的nginx地址nginx代理附件地址和附件下载服务(保证代理和服务在同一个ip 端口下)

location /protected_files {
    internal;     # internal 表示这个路径只能在 Nginx 内部访问,不能用浏览器直接访问防止未授权的下载
    alias /mnt/files;
}
location /gsdss-api/ {
       #OPTIONS请求处理
       if ($request_method = 'OPTIONS') {
               add_header 'Access-Control-Max-Age' 1728000;
               add_header Access-Control-Allow-Origin *;
               add_header Access-Control-Allow-Credentials true;
               add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
               add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,token,orgcode';
               return 200;
       }
       proxy_pass 网关地址;
       proxy_set_header Host $host;
       proxy_set_header X-Real-IP $remote_addr;
       proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
       client_max_body_size 100m;
       proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
}

java处理鉴权后直接重定向到nginx代理地址

    public void downloadByLink(HttpServletResponse response, String fileId) {
        //查询附件信息
        AttachmentResp resp = attachmentService.findByAttachId(fileId);
        //鉴权实际已经通过gateway完成
        try {
            String fileName = URLEncoder.encode(resp.getFileName(), "UTF-8");
            response.addHeader("Content-Disposition", "attachment;filename=" + fileName);
            response.setHeader("X-Accel-Redirect", "/upload" + resp.getPath()); //设置URI给nginx进行内部的跳转
            response.setHeader("X-Accel-Limit-Rat", "202400"); //限速
        } catch (UnsupportedEncodingException e) {
            log.error("文件下载失败 ", e);
            throw new BusinessException("文件下载失败");
        }
    }

总结

常规请求路径

前端nginx:前端访问nginx代理网关路径

后端nginx:

  • 代理网关路径转发到实际网关地址
  • 网关分发到附件服务
  • 附件服务处理请求

为了保证nginx代理的下载路径和附件下载服务在同一ip和端口那么这个nginx代理需要2层实现

 到此这篇关于springboot X-Accel-Redirect 大文件下载实现的文章就介绍到这了,更多相关springboot X-Accel-Redirect 大文件下载内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 详解使用Spring的BeanPostProcessor优雅的实现工厂模式

    详解使用Spring的BeanPostProcessor优雅的实现工厂模式

    这篇文章主要介绍了详解使用Spring的BeanPostProcessor优雅的实现工厂模式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-07-07
  • Mockito如何mock静态方法问题

    Mockito如何mock静态方法问题

    本文介绍了如何在Mockito 3.4.0版本及以上版本中mock静态方法,包括如何在pom文件中添加相关jar包、如何使用Mockito.mockStatic(Class mockClass)方法以及注意事项等
    2025-02-02
  • Java对象和Map之间相互转换的五种方法

    Java对象和Map之间相互转换的五种方法

    在Java开发中,经常需要将Java对象转换成Map,或者反过来将Map转换成Java对象,这种转换在很多场景下都非常有用,比如在序列化和反序列化过程中、在数据传输和持久化时、或者在进行对象属性的批量操作时,本文将介绍几种不同的方法来实现Java对象和Map之间的相互转换
    2025-02-02
  • 如何解决java.util.concurrent.CancellationException问题

    如何解决java.util.concurrent.CancellationException问题

    这篇文章主要介绍了如何解决java.util.concurrent.CancellationException问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-05-05
  • Java HtmlEmail 邮件发送的简单实现代码

    Java HtmlEmail 邮件发送的简单实现代码

    下面小编就为大家带来一篇Java HtmlEmail 邮件发送的简单实现代码。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-06-06
  • 使用Feign实现微服务间文件传输

    使用Feign实现微服务间文件传输

    这篇文章主要为大家详细介绍了使用Feign实现微服务间文件传输,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-04-04
  • 浅谈java随机数的陷阱

    浅谈java随机数的陷阱

    这篇文章主要介绍了浅谈java随机数的陷阱,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-09-09
  • 使用Java实现签字功能的示例代码

    使用Java实现签字功能的示例代码

    这篇文章主要为大家详细介绍了如何使用Java实现签字功能,同时支持将签字图像保存为PNG格式和将签字添加到PDF文档中,感兴趣的可以了解下
    2024-02-02
  • mybatis-plus指定字段模糊查询的实现方法

    mybatis-plus指定字段模糊查询的实现方法

    最近项目中使用springboot+mybatis-plus来实现,所以下面这篇文章主要给大家介绍了关于mybatis-plus实现指定字段模糊查询的相关资料,需要的朋友可以参考下
    2022-04-04
  • SpringBoot登录、退出、获取用户信息的session处理方案

    SpringBoot登录、退出、获取用户信息的session处理方案

    这篇文章主要介绍了SpringBoot登录、退出、获取用户信息的session处理,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-08-08

最新评论