前言
目前,大多数系统都是跟文件弱交互,所以对上传下载功能都没有过多的关注。文件上传方案请移步到文件上传方案&RestTemplate全链路流式上传,本章节主要讲的是文件下载方案。
下载方案
目前小编下载文件主要采取3种方案,分别是应用服务直连对象存储服务器(或者文件服务器)流式下载、通过分享对象存储服务器(或者文件服务器)临时链接进行下载、应用服务重定向到对象存储服务器(或者文件服务器)临时链接进行下载。
应用服务直连对象存储服务器(或者文件服务器)流式下载
目前网络上流传的大部分都是通过应用服务器和文件服务器交互,然后通过流式下载,如下例子。
//对响应进行流式处理而不是将其全部加载到内存中
restTemplate.execute(url, HttpMethod.GET, requestCallback, clientHttpResponse -> {
byte[] buffer = new byte[1024];
try (InputStream inputStream = clientHttpResponse.getBody(); BufferedInputStream bis = new BufferedInputStream(inputStream)) {
OutputStream os = response.getOutputStream();
response.setContentType("application/octet-stream");
if (StringUtils.isNotBlank(fileName)) {
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName,
"UTF-8"));
}
int i = bis.read(buffer);
while (i != -1) {
os.write(buffer, 0, i);
i = bis.read(buffer);
}
}
return null;
});
这种方式,弊端在于:假如在应用系统跟大文件交互比较多的场景下,下载大文件时间会比较长,会受到业务系统的带宽和请求连接数限制,有可能会导致业务系统需要跟着文件下载量进行对业务系统进行横向扩容。
通过分享对象存储服务器(或者文件服务器)临时链接进行下载
本例子以minio为例,每次用户下载文件的时候通过业务系统进行鉴权,鉴权成功后,业务系统从minio获取文件分享临时链接,然后把链接返回用户,用户通过分享链接直接下载文件,如下图所示。
这种方式的弊端在于,假如不是放在浏览器访问的话(例如后端调用),需要对接2个经过两步,会比以前直连下载多一个步骤。
应用服务重定向到对象存储服务器(或者文件服务器)临时链接进行下载
本例子以minio为例,每次用户下载文件的时候通过业务系统进行鉴权,鉴权成功后,业务系统从minio获取文件分享临时链接,然后把用户请求重定向到临时链接上,然后就可以从minio服务直接下载文件,跟第二种方式图示一致。
emm~,目前这种方式,是小编最为推荐的方式,既能减轻应用服务的压力,也能直接通过浏览器访问,不需要两步操作。
注意:
假如同学们的minio上存储的文件名跟业务系统上文件名不一致,那么我们需要在网关上做些操作。小编用的是nginx,在minio返回的链接上追加了一个参数customFileName,然后在nginx上做判断,然后根据文件名来下载。
minio分享链接,customFileName是小编添加的参数,用于自定义文件名:
https://minioUrl?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=root%2F20210721%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20210721T092613Z&X-Amz-Expires=18000&X-Amz-SignedHeaders=host&X-Amz-Signature=db7e58373cdbe13cfdbdfdeb4f61d91048908d2080ca11549672178ff246c257&customFileName=floorheight.json
//nginx修改配置
if ( $args ~ "^(.*)(&.*)(&.*)(&.*)(&.*)(&.*)&customFileName=(.*)$") {
//minio下载链接会有固定6个参数,并且有签名,所以转发的时候不能带上我们自定义参数
set $args $1$2$3$4$5$6;
//用自定义文件名下载
add_header Content-Disposition 'attachment;filename=$7';
}
总结
一般应用服务没有很多文件下载的需求,所以很多同学都不需要考虑这个问题。假如各位同学的系统上有很多、很大文件下载的需求,并且还没有头绪如何优化,相信小编的这篇文章能给你们带来启发/帮助。