今天碰到一個比較奇怪的技術問題,使用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" />