Spring REST / Swagger / Postman - 正在下载损坏/空白文件

Posted

技术标签:

【中文标题】Spring REST / Swagger / Postman - 正在下载损坏/空白文件【英文标题】:Spring REST / Swagger / Postman - Damaged/Blank File being dowloaded 【发布时间】:2017-05-15 21:32:58 【问题描述】:

我关注this 发布的功能:客户端现在可以下载文件(即 csv、pdf 和 zip)。

但是我得到的是空白的 pdf,或者在尝试使用 zip 文件时,它已经损坏了。只有 CSV 可以正常工作

我检查了标题,一切似乎都符合标准。我什至没有使用“application/octet-stream”,而是为 pdf 使用“application/pdf”,为 csv 使用“application/csv”,为 zip 使用“application/zip”,只是为了避免客户端出现任何问题。我正在使用 swagger 2.4 来测试我的 api。这是我的代码。

@CrossOrigin
@Controller
public class ReportRestController 


@Autowired
ReportService reportService;

@Value("$report.temp.directory") // used for storing file in local
private String reportLocation;

@ApiImplicitParams(
        @ApiImplicitParam(name = "Authorization", value = "Authorization", required = true, dataType = "string", paramType = "header"),
        @ApiImplicitParam(name = "Auth-Provider", value = "Auth-Provider", required = true, dataType = "string", paramType = "header"),)
@RequestMapping(value = "/report/type/format", method = RequestMethod.POST)
public void getList(@RequestHeader(value = "UserId", required = false) Long userId,
        @RequestHeader(value = "TeamId", required = false) Long teamId,
        @RequestHeader(value = "CustomerId", required = true) Long customerId,
        @PathVariable("type") String type, @PathVariable("format") String formate,
        @RequestBody ReportRequestObj reportobj, HttpServletResponse response) 

    String filename = reportService.getReport(customerId, userId, teamId, type, formate, reportobj);
    Path pathfile = Paths.get(reportLocation, filename);
    File file = pathfile.toFile();
    if (file.exists()) 
        String fileExtension = FilenameUtils.getExtension(filename);
        if(CommonConstants.CSV.equals(fileExtension))
            response.setContentType("application/csv");
        else if(CommonConstants.PDF.equals(fileExtension))
            response.setContentType("application/pdf");
        else if(CommonConstants.ZIP.equals(fileExtension))
            response.setContentType("application/zip");
        
        response.addHeader("Content-Disposition", "attachment; filename=" + filename);
        response.setContentLength((int) file.length());
        response.setHeader("Content-Transfer-Encoding", "binary");
        try(FileInputStream fileInputStream = new FileInputStream(file)) 
            IOUtils.copy(fileInputStream,response.getOutputStream());
            response.getOutputStream().flush();
            //response.flushBuffer();
         catch (IOException ex) 
            log.error("Error while sending the file: for customerId: ,userId:",
                    file.getPath(), customerId, userId);
        
    

请让我知道我做错了什么或遗漏了什么?

编辑 1:我附上了我得到的响应标头:


 "date": "Sun, 01 Jan 2017 19:11:13 GMT",
 "x-content-type-options": "nosniff",
 "access-control-max-age": "3600",
 "content-disposition": "attachment;   filename=localhost-blob-abcd.pdf",
"content-length": "172962",
"x-xss-protection": "1; mode=block",
"x-application-context": "report-server:8095",
"pragma": "no-cache",
"server": "Apache-Coyote/1.1",
"x-frame-options": "DENY",
"access-control-allow-methods": "POST, PUT, GET, OPTIONS, DELETE",
"content-type": "application/pdf;charset=UTF-8",
"access-control-allow-origin": "*",
"cache-control": "no-cache, no-store, max-age=0, must-revalidate, no-cache",
"access-control-allow-headers": "Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With, Auth-Provider, UserId, TeamId, Lang, CustomerId",
"expires": "0"

【问题讨论】:

【参考方案1】:

好的,这段代码对我有用:

package com.example;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;

import javax.servlet.http.HttpServletResponse;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.CacheControl;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@SpringBootApplication
public class DemoApplication 

    public static void main(String[] args) 
        SpringApplication.run(DemoApplication.class, args);
    

    @Controller
    public class DownloadController 

        @RequestMapping("/download")
        public ResponseEntity<InputStreamResource> download() throws FileNotFoundException 
            final File file = new File("file.pdf");
            return ResponseEntity.ok()
                    .contentLength(file.length())
                    .contentType(MediaType.APPLICATION_PDF)
                    .cacheControl(CacheControl.noCache())
                    .header("Content-Disposition", "attachment; filename=" + file.getName())
                    .body(new InputStreamResource(new FileInputStream(file)));
        
    

Spring Boot 没有什么特别之处,你可以在普通的 Spring MVC 中使用。

也许这是一个像这样的 Swagger 问题:File download via content-disposition header corrupts file,而不是服务器端问题。您是否尝试过使用其他工具测试此 API 调用?例如curl 永远不会让我失望。

【讨论】:

感谢您的快速回复。但响应是一样的——黑色 PDF 和损坏的 zip 文件。 @balboa_21 提供了使用 ResponseEntity API 实现缓冲文件以响应副本的示例代码。 嗨@yanys,还是同样的问题。空白 pdf + zip 文件已损坏。只有 csv 工作正常。当然,我会改变标题,我不知道还能放什么,所以我写了 Spring Boot。谢谢。顺便说一句,我正在使用 swagger 进行测试。 嗨@balboa_21,可能是像File download via content-disposition header corrupts file 这样的Swagger 问题,而不是服务器端问题。您是否尝试过使用其他工具测试此 API 调用?例如curl 永远不会让我失望。 嗨@yanys,感谢您让我知道我尝试使用curl,swagger生成curl -X而不是curl -o,它工作得很好。你能把这个评论作为编辑来回答,这样我就可以把它标记为接受了。我也会更新标题。

以上是关于Spring REST / Swagger / Postman - 正在下载损坏/空白文件的主要内容,如果未能解决你的问题,请参考以下文章

Spring REST / Swagger / Postman - 正在下载损坏/空白文件

为spring boot 写的Controller中的rest接口配置swagger

在带有 spring-boot rest 和 Swagger 的标头中使用 utf-8 字符时未加载响应

Spring Boot整合Swagger2构建RESTful API

端口6000无法访问Spring Boot Swagger REST服务器由于localhost不安全错误

SpringBoot+rest接口+swagger2生成API文档+validator+mybatis+aop+国际化