使用FileSystemResource强制文件下载文件时如何设置'Content-Disposition'和'Filename'?

Has*_*mil 27 java spring content-disposition spring-3

设置Content-Disposition=attachmentfilename=xyz.zip使用Spring 3 的最合适,最标准的方法是FileSystemResource什么?

该动作如下:

@ResponseBody
@RequestMapping(value = "/action/{abcd}/{efgh}", method = RequestMethod.GET, produces = "application/zip")
@PreAuthorize("@authorizationService.authorizeMethod()")
public FileSystemResource doAction(@PathVariable String abcd, @PathVariable String efgh) {

    File zipFile = service.getFile(abcd, efgh);

    return new FileSystemResource(zipFile);
}
Run Code Online (Sandbox Code Playgroud)

虽然该文件是一个zip文件,因此浏览器总是下载该文件,但我想明确提到该文件为附件,并提供与文件实际名称无关的文件名.

可能有解决此问题的方法,但我想知道正确的Spring和FileSystemResource实现此目标的方法.

PS此处使用的文件是临时文件,在JVM存在时标记为删除.

Has*_*mil 30

@RequestMapping(value = "/action/{abcd}/{efgh}", method = RequestMethod.GET)
@PreAuthorize("@authorizationService.authorizeMethod(#id)")
public HttpEntity<byte[]> doAction(@PathVariable ObjectType obj, @PathVariable Date date, HttpServletResponse response) throws IOException {
    ZipFileType zipFile = service.getFile(obj1.getId(), date);

    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
    response.setHeader("Content-Disposition", "attachment; filename=" + zipFile.getFileName());

    return new HttpEntity<byte[]>(zipFile.getByteArray(), headers);
}
Run Code Online (Sandbox Code Playgroud)

  • 简短回答`response.setHeader("Content-Disposition","attachment; filename ="+ YOUR_FILE_NAME);` (7认同)
  • 请注意,如果文件名未正确清理,此解决方案可能会导致简单的跨站点脚本攻击! (3认同)
  • 但请注意,如果文件名包含非"标记"字符(例如空格,非ASCII和某些分隔符),则会中断. (2认同)
  • 避免仅代码答案。提供有关代码段的一些解释! (2认同)
  • 将文件名放在双引号 `"` 之间。 (2认同)

Jef*_*ima 19

除了可接受的答案外,Spring还具有为此目的而特定的类ContentDisposition。我相信它可以处理文件名清理。

      ContentDisposition contentDisposition = ContentDisposition.builder("inline")
          .filename("Filename")
          .build();

      HttpHeaders headers = new HttpHeaders();
      headers.setContentDisposition(contentDisposition);
Run Code Online (Sandbox Code Playgroud)

  • 如果您必须使用其构建器构建`HttpServletResponse`或`ResponseEntity`,您仍然可以使用`ContentDisposition`类为您生成标头字符串:`response.setHeader(HttpHeaders.CONTENT_DISPOSITION, contentDisposition.toString()) ;` 它将负责转义必要的字符。 (5认同)
  • 从 Spring 5.3 开始,您可以使用 `ContentDisposition.inline()` 或 `ContentDisposition.attachment()` 而不是 `ContentDisposition.builder("inline")`。 (2认同)

Kum*_*mar 13

 @RequestMapping(value = "/files/{file_name}", method = RequestMethod.GET)
    @ResponseBody
    public FileSystemResource getFile(@PathVariable("file_name") String fileName,HttpServletResponse response) {
        response.setContentType("application/pdf");      
        response.setHeader("Content-Disposition", "attachment; filename=somefile.pdf"); 
        return new FileSystemResource(new File("file full path")); 
    }
Run Code Online (Sandbox Code Playgroud)


val*_*tis 10

这是Spring 4的一种替代方法。请注意,此示例显然未使用有关文件系统访问的良好做法,这只是为了演示如何声明性地设置某些属性。

@RequestMapping(value = "/{resourceIdentifier}", method = RequestMethod.GET, produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
// @ResponseBody // Needed for @Controller but not for @RestController.
public ResponseEntity<InputStreamResource> download(@PathVariable(name = "resourceIdentifier") final String filename) throws Exception
{
    final String resourceName = filename + ".dat";
    final File iFile = new File("/some/folder", resourceName);
    final long resourceLength = iFile.length();
    final long lastModified = iFile.lastModified();
    final InputStream resource = new FileInputStream(iFile);

    return ResponseEntity.ok()
            .header("Content-Disposition", "attachment; filename=" + resourceName)
            .contentLength(resourceLength)
            .lastModified(lastModified)
            .contentType(MediaType.APPLICATION_OCTET_STREAM_VALUE)
            .body(resource);
}
Run Code Online (Sandbox Code Playgroud)