Spring MVC:下载文件的编码错误

时间:2015-02-18 14:18:38

标签: java spring google-chrome spring-mvc servlets

我尝试使用spring mvc servlet了解pdf文件下载中的奇怪行为。

以下是用于下载文件的控制器代码:

@RequestMapping(value = "/handler/{id}", method = RequestMethod.GET)
public HttpEntity<byte[]> report(@PathVariable("id") Long id, 
        HttpServletResponse response,
        HttpServletRequest request) {
    byte[] bytes = service.reportById(id);

    return DownloadUtil.downloadFile(response, "application/pdf",
           "Filename.pdf", bytes);
}

public static HttpEntity<byte[]> downloadFile(
    final HttpServletResponse response, 
    final String contentType, 
    final String fileName, 
    final byte[] item){

    HttpHeaders header = new HttpHeaders();
    header.setContentType(MediaType.valueOf(contentType));
    header.set("Content-Disposition", "inline; filename=\"" + fileName +"\"");
    header.set("Content-Transfer-Encoding", "application/octet-stream");  

    header.setContentLength(item.length);
    return new HttpEntity<byte[]>(item, header);
}   

当pdf在chrome pdf viewer中显示时,它可以正常工作。请求/响应标头:

请求:

GET /path/19649/download HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.76 Safari/537.36
Referer: http://path/byDitta
Accept-Encoding: gzip, deflate, sdch
Accept-Language: it,en-US;q=0.8,en;q=0.6
Cookie: JSESSIONID=09CEA1438ACED879CDD96877BB536022; _ga=GA1.1.2013320496.1416898514

响应:

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Disposition: inline; filename="file.pdf"
Content-Transfer-Encoding: application/octet-stream
Content-Type: application/pdf;charset=UTF-8
Content-Length: 296750
Date: Tue, 10 Mar 2015 09:39:05 GMT 

当我保存pdf查看器中显示的pdf时,我有这个请求/响应标题:

请求:

GET /path/19649/download HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Referer: /path/19649/download
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.76 Safari/537.36
Accept-Encoding: gzip, deflate, sdch
Accept-Language: it,en-US;q=0.8,en;q=0.6
Cookie: JSESSIONID=09CEA1438ACED879CDD96877BB536022; _ga=GA1.1.2013320496.1416898514

响应:

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Disposition: inline; filename="file.pdf"
Content-Transfer-Encoding: application/octet-stream
Content-Type: application/pdf;charset=UTF-8
Content-Length: 296750
Date: Tue, 10 Mar 2015 09:40:29 GMT

差异在accept请求标题中,我认为。在保存pdf请求中遗漏了它。

问题在于,当保存此文件时,其编码错误会导致损坏。

奇怪的是,我在另一个项目中使用〜相同的代码来做同样的事情并且它有效。所以我想,可能是servlet配置中的东西?

如何强制下载正确的编码?

2 个答案:

答案 0 :(得分:3)

来自评论:

  

比较文件大小,工作pdf为227403字节,另一个为303206字节

这表明数据为Base64 encoded。我不明白为什么会这样;大多数情况下,当服务器认为客户端无法处理二进制数据时(例如,当您执行AJAX请求时),就会产生这种效果。

[编辑] 安装Fiddler等代理服务器,可以查看服务器发送给浏览器的原始数据。尝试只创建一个小PDF,以使这更容易。

使用这些工具,您可以找出编码数据的人。

答案 1 :(得分:0)

如果您的pdf文件生成良好,我认为您应该尝试这种方式:

         @RequestMapping(value = "clients/city")
         @ResponseBody
private OutputStream getCity(HttpServletRequest request,HttpServletResponse   response) throws IOException, JRException {
  String path=request.getRealPath("resources/files");
  createFileService.SpravkaCity(path); 
 //      response.setContentType("text/plain");      
 //      response.setHeader("Content-Disposition", "attachment;   filename=reestr.xls");
  File f=new File(path+"/city.pdf");
  response.setContentType("application/pdf");
 //      response.setHeader("Content-Transfer-Encoding", "binary");
  response.setHeader("Content-Length", String.valueOf(f.length()));
  response.setHeader("Content-Disposition", "inline; filename=city.pdf");
  Path p = Paths.get(path+"/city.pdf");
  response.getOutputStream().write(Files.readAllBytes(p));
  return response.getOutputStream();
} 

希望它会对你有所帮助。