开发了一个下载文件的接口,使用 Content-Disposition
指定默认下载附件文件名,但是每次下载默认文件名与指定的不一致
基础环境#
接口代码#
出于某些原因,这里只展示下载相关的代码。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.CacheControl;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import java.io.File;
import java.net.URLEncoder;
import java.util.concurrent.TimeUnit;
@RestController
@RequestMapping({"/api/v1"})
public class DownloadController {
private Logger logger = LoggerFactory.getLogger(getClass());
@GetMapping("/download/{id}")
@ApiOperation("Download file by id")
public ResponseEntity<FileSystemResource> downloadFile(@PathVariable("id") Long id) throws Exception {
String url = String.format("data/%s.pdf", id);
File file = new File(url);
if (!file.isFile()) {
logger.error("ERROR download file, can not find the file, ID: {}, url: {}", id, url);
return ResponseEntity.notFound().build();
}
return ResponseEntity
.ok()
.header("Content-Disposition", "attachment; filename=" + URLEncoder.encode(file.getName(), "utf-8"))
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.contentLength(file.length())
.cacheControl(CacheControl.maxAge(60, TimeUnit.SECONDS))
.body(new FileSystemResource(file));
}
}
|
具体现象#
在点击下载的过程中,如果下载的文件ID为 1
时,默认下载的文件名则为 1
, 而非Response header 中设置的filename 1.pdf
原因排查#
确定排查范围#
接口已经经过测试,除默认设置的文件名不生效外,暂未发现其他问题。而默认设置的文件名由 .header("Content-Disposition", "attachment; filename=" + URLEncoder.encode(file.getName(), "utf-8"))
这一行控制,则将范围设置为 Response header Content-Disposition 相关的问题
查询相关信息#
在确定了排查范围之后,根据相关的关键词查询信息。
- 根据关键词
http response attachment filename
搜索相关的信息,在MDN Web Docs上找到了对于Content-Disposition的描述
- MDN Web Docs中描述的格式如下
Content-Disposition: attachment; filename="filename.jpg"
- 将接口返回的结果
Content-Disposition: attachment; filename=filename.pdf
与文档描述进行对比,发现 filename=
后面缺失了 "
符号。
- 修改相关的代码,添加
"
符号,将相关的代码修改如下后进行测试
1
2
3
4
5
6
7
|
return ResponseEntity
.ok()
.header("Content-Disposition", "attachment; filename=\"" + URLEncoder.encode(file.getName(), "utf-8") + "\"")
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.contentLength(file.length())
.cacheControl(CacheControl.maxAge(60, TimeUnit.SECONDS))
.body(new FileSystemResource(file));
|
解决方案#
修改代码,在 filename=
后面添加 "