SpringMVC,SpringBoot文件下载

前言

最近严查security, 导致原来暴露出去的s3不能用了,不允许public的s3,暂时的折中方案是自己做跳转。于是需要在SpringMVC中实现文件下载功能。

关于文件存储的设计

文件存储通常用作对象存储,业界标准就是AWS s3, 国内的七牛也差不多。不想自建的话,采用这种第三方存储是很方便的。但是,有写地方需要注意。

安全问题

就像这次整改遇到的,权限问题大概是对象存储必须具备的。s3的权限特别多和复杂,可以做到认证user访问; 指定ip访问; 指定IAM Role访问; 指定第三方登陆比如Facebook,google的认证,设置自己的认证,这里是指Cognito。

地址路径的健壮性

review代码的时候发现了几个严重的问题,地址问题尤为重要,简直就是bug一样。首先,db存储的文件路径不应该包含域名前缀,像这次整改图片存储就导致以前db里的数据不能用了。db只能存储相对路径,即当指定改类型前缀后,变化的部分路径。。 然后就是 需要一个域名,对于公开的地址,需要一个域名来维护,而不是直接指定当前的文件服务器。比如一个公开的s3可能是这样的:https://mybucket.s3.amazonaws.com/keyprefix/key. 如果我们变更了s3的bucket,那么这个地址就废弃了,这个很有可能发生的。因此,用一个我们自己的域名指向s3可以屏蔽这个细节。同理,如果写死了文件服务器的地址,当文件服务器变更的时候,公开的文件将全部失效。

如何使用SpringMVC下载文件

我们可以简单的在HttpServletResponse的OutputStream里写入我们的文件流,这样就可以实现文件下载。但这个做法感觉有点太直接了,推荐使用Spring的ResponseEntity来做。

@RequestMapping(value = "/static/filename")
public ResponseEntity<InputStreamResource>(HttpServletResponse response) {
    final ObjectMetadata objectMetadata = s3Object.getObjectMetadata();

    return ResponseEntity.ok()
            .header("Access-Control-Allow-Origin", "*")
            .cacheControl(CacheControl.maxAge(maxAge, TimeUnit.DAYS).cachePublic())
            .allow(HttpMethod.GET, HttpMethod.OPTIONS)
            .contentLength(objectMetadata.getContentLength())
            .contentType(MediaType.valueOf(objectMetadata.getContentType()))
            .body(new InputStreamResource(s3Object.getObjectContent()));
}
  1. 问题核心在于返回ResponseEntity<InputStreamResource>
  2. ResponseEntity是SpringMVC里统一封装的返回值response信息
  3. InputStreamResource则是接收一个输入流InputStream的结果集
  4. 然后可以设置浏览器缓存,这个对用户刷新页面挺重要的
  5. 对于图片和js等,需要设置contentType为png或者js等

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏技术博文

http状态码一览表

http状态码一览表 1**:请求收到,继续处理 2**:操作成功收到,分析、接受 3**:完成此请求必须进一步处理 4**:请求包含一个错误语法或不能完成 5...

3407
来自专栏Kirito的技术分享

Re:从零开始的Spring Session(三)

上一篇文章中,我们使用Redis集成了Spring Session。大多数的配置都是Spring Boot帮我们自动配置的,这一节我们介绍一点Spring Se...

34311
来自专栏Python自动化测试

python接口测试之401错误的分析和解决(十七)

通过一个案例来分析在HTTP的请求中403错误的解决以及HTTP的状态码中403怎么理解,见发送一个请求后,返回的状态码,见如下的信息:

1136
来自专栏battcn

一起来学SpringBoot | 第十五篇:actuator与spring-boot-admin 可以说的秘密

一起来学SpringBoot | 第十四篇:强大的 actuator 服务监控与管理 中介绍了 actuator 的作用,细心的朋友可能会发现通过 http r...

1192
来自专栏优启梦

Servlet HTTP 状态码大全列表

状态行包括 HTTP 版本(在本例中为 HTTP/1.1)、一个状态码(在本例中为 200)和一个对应于状态码的短消息(在本例中为 OK)。

3617
来自专栏Ryan Miao

HTTP status code

被一个问题耽搁了好久,最后才恍然。这是关于HTTP status的。 使用feign进行http请求,结果总是抛出异常: read 405.由于不了解feign...

3867
来自专栏程序猿DD

从零开始的Spring Session(三)

新媒体管家 上一篇文章中,我们使用Redis集成了Spring Session。大多数的配置都是Spring Boot帮我们自动配置的,这一节我们介绍一点Spr...

2738
来自专栏文大师的新世界

3. spring security & oauth2

解释看代码字面意思就懂了,没什么特殊的,还可以修改比如登录表单里的用户名和密码的名字,还可以添加各种登录成功之后的handler等等,写法都一样。

1242
来自专栏程序猿DD

从零开始的Spring Security Oauth2(一)

前言 今天来聊聊一个接口对接的场景,A厂家有一套HTTP接口需要提供给B厂家使用,由于是外网环境,所以需要有一套安全机制保障,这个时候oauth2就可以作为一个...

3426
来自专栏我的博客

HTTP 状态码汇总

400 Bad request(错误请求) 401.1 Logon failed(登录失败) 401.2 Logon failed due to serve...

3398

扫码关注云+社区