问题描述:在使用HttpClient进行文件下载时,获取的HttpResponse响应头中"Content-Disposition"中的filename为中文时产生了乱码。
首先来看下如何使用HttpClient进行文件下载:
/** * 通过url使用HttpClient下载文件 * @param url 传递的下载路径(http:xxxxxx....) */ public void downLoadFile(String url) throws IOException { // 生成一个httpclient对象 CloseableHttpClient httpclient = HttpClients.createDefault(); HttpGet httpget = new HttpGet(url); HttpResponse response = httpclient.execute(httpget); HttpEntity entity = response.getEntity(); InputStream in = entity.getContent(); File file = new File("D:/temp/123.jpg");//这里为存储路径/xx/xx.. FileOutputStream fout = new FileOutputStream(file); int a = -1; byte[] tmp = new byte[1024]; while ((a = in.read(tmp)) != -1) { fout.write(tmp, 0, a); //注意这里如果用OutputStream.write(buff)的话,图片会失真,大家可以试试 } fout.flush(); fout.close(); in.close(); httpclient.close(); }
引起图片失真的问题:
如果在进行读写操作时,写成了:
而不是:
会引起图片失真。造成原因就是在进行读写操作时,找不到结尾的标志。
乱码问题解决:
一般我们在使用HttClient进行文件下载时,需要获取到文件的名称及类型,但是很多时候提供给我们的url中是不包含这些信息的,所以需要通过HttpResponse中的信息来获取这些。
将上面下载时获取的response作为参数进行传递。
/** * 获取response header中Content-Disposition中的filename值 * @param response * @return */ private String getFileName(HttpResponse response) { Header contentHeader = response.getFirstHeader("Content-Disposition"); String filename = UUID.randomUUID().toString().replace("-",""); if (contentHeader != null) { HeaderElement[] values = contentHeader.getElements(); if (values.length == 1) { NameValuePair param = values[0].getParameterByName("filename"); if (param != null) { try { String code1 = "windows-1252"; String code2 = "ISO-8859-1"; String name = param.getValue(); //判断现在的编码格式 if(name.equals(new String(name.getBytes(code1),code1))){ //GBK为铁塔在Content-Disposition中filename使用的编码格式 filename = new String(name.getBytes(code1), "GBK"); if(!EncodeUtils.isLetterDigitOrChinese(filename)){ filename=URLDecoder.decode(param.getValue(),"utf-8"); } }else if(name.equals(new String(name.getBytes(code2),code2))){ filename = new String(name.getBytes(code2), "GBK"); if(!EncodeUtils.isLetterDigitOrChinese(filename)){ filename=URLDecoder.decode(param.getValue(),"utf-8"); if(!EncodeUtils.isLetterDigitOrChinese(filename)){ filename=URLDecoder.decode(param.getValue(),"utf-8"); } } } //filename = param.getValue(); } catch (Exception e) { e.printStackTrace(); } } } } return filename; }
一般我们获取到的信息,如果没有进行特殊处理,都是默认的ISO-8859-1编码格式的,但是在windows10的系统下,有时会将ISO-8859-1编码认为是window-1252进行传递(这也是个坑)。这样就会导致在进行解码时,解出来的还是乱码。
这里我针对传递的参数经过了GBK编码和普通编码的处理,不针对所有的乱码都能解决,但是对一些按照正常解码方式还无法进行解码的可以尝试用这种方式进行解码。
一般的解码方式:filename = URLDecoder.decode(param.getValue(),"UTF-8");
或者:filename = new String(param.getValue().getBytes(),"UTF-8");
上面的isLetterDigitOrChinese:是我自定义的一个判断解析后的文件名是否符合要求的正则。
/** 判断是否只包含数字,字母,汉字和英文的(),.,-,_ 和中文的()**/ public static boolean isLetterDigitOrChinese(String str) { String regex = "^[a-z_0-9A-Z-.()()\u4e00-\u9fa5]+$";//其他需要,直接修改正则表达式就好 return str.matches(regex); }