今天碰到一个比较奇怪的技术问题,使用Spring MVC作文件下载时,FireFox、Chrome浏览器下载都没有遇到问题,IE 11缺不能正常下载,老是提示“可能已删除或移动文件”。你们都说是IE浏览器不支持HTTP CREATED(201)状态码,但事实上我返回的是HTTP OK(200)状态码,但问题依然得不到解决,所以引发此问题的缘由跟这个HTTP状态码是无关的。java
看看下载到的文件,文件其实已经下载下来了,只不过其文件扩展名为“.w2s1z41.partial”,将扩展名去掉,获得的是一个zip文件,该zip文件能够正常解压缩。所以判定,文件已所有下载完成。浏览器
再来看看服务端的问题代码(针对IE不能正常下载,其余浏览器正常):tomcat
/** * 客户端软件的更新下载 * @return * @throws HttpErrorException */ @RequestMapping(value="/client/update", method=RequestMethod.GET) public ResponseEntity<byte[]> update() throws HttpErrorException { String zipFile = "E:\\proj-svn-local\\tmp\\PPMS-Client-Setup_x86_1.0.35.zip"; File downloadZip = new File(zipFile); HttpHeaders headers = new HttpHeaders(); headers.setContentDispositionFormData("attachment", downloadZip.getName()); headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); ResponseEntity<byte[]> responseEntity; try { responseEntity = new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(downloadZip), headers, HttpStatus.OK); } catch (IOException e) { modelMsg = "Read zip file error: " + downloadZip.getPath();; throw new HttpErrorException(modelMsg, HttpStatus.INTERNAL_SERVER_ERROR.value()); } return responseEntity; }
通过多番调试,最终发现问题的所在,原来问题出在下面这行上:app
headers.setContentDispositionFormData("attachment", downloadZip.getName());
这行代码的做用是用于告诉浏览器如何显示本次请求响应所附加的文件,“attachment”表示是让浏览器如下载附件的形式打开文件。按道理,这也没错。经过调试打印出其设置内容,获得文本以下:svn
[form-data; name="attachment"; filename="PPMS-Client-Setup_x86_1.0.35.zip"]
问题出现了,前面出现了“form-data”字符,此标识应该是在文件上传时才使用(上传文件时通常都将文件放置在表单域中),而当前要作的是“文件下载”,这样不出问题才怪啊。取而代之的headers.set方法,而非headers.setContentDispositionFormData()方法,因此将问题行代码更换成下述代码,问题即可获得解决:spa
headers.set("Content-Disposition", "attachment; filename=\"" + downloadZip.getName() + "\"");
解决中文名乱码问题
.net
@RequestMapping("/download/{fileId}") public ResponseEntity<byte[]> download(HttpServletRequest request,HttpSession httpSession,@PathVariable String fileId) throws IOException { Map<String, Object> cacheFile = getCacheFileBySession(httpSession, fileId); System.out.println("encode:"+request.getCharacterEncoding()); //中文文件名支持 String encodedfileName = null; String agent = request.getHeader("USER-AGENT"); if(null != agent && -1 != agent.indexOf("MSIE")){//IE encodedfileName = java.net.URLEncoder.encode(((String)cacheFile.get("fileName")),"UTF-8"); }else if(null != agent && -1 != agent.indexOf("Mozilla")){ encodedfileName = java.net.URLEncoder.encode(((String)cacheFile.get("fileName")),"UTF-8"); }else{ encodedfileName = java.net.URLEncoder.encode((String)cacheFile.get("fileName"),"UTF-8"); } HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); //headers.setContentDispositionFormData("attachment", (String)cacheFile.get("fileName")); headers.set("Content-Disposition", "attachment; filename=\"" + encodedfileName + "\""); return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(new File((String) cacheFile.get("downLoadPath"))), headers, HttpStatus.OK); }
tomcat /config/server.xml 添加 URIEncoding="UTF-8"调试
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" URIEncoding="UTF-8" />