IE浏览器下载文件中文文件名乱码问题解决

简介: IE浏览器下载文件中文文件名乱码问题解决

处理过程

根据IE的F12中的log提示,是因为http头信息中的编码替换了html文件中的编码。我最初的思路是设置Tomcat默认编码,但是我发现我已经在Server.xml中设置过,想到这里我想到了上篇文章的文件重命名的问题,准备去写个filter去修改http响应头,但是我突然明白,SpringMVC应该会处理过,但是为什么无效呢,这种成熟的框架不应该会有bug存在,于是我尝试在SpringMVC的xml中配置SourceHttpMessageConverter等转换器,都无效。


发现原因

后来发现web.xml是配置了编码处理的, 内容如下:

//第一个工具类中的下载方法:
    /**
     * 下载
     * @param request
     * @param response
     * @param fileName
     * @param downLoadPath
     * @param contentType
     * @throws IOException 
     * @throws Exception
     */
    public static void download(HttpServletRequest request,HttpServletResponse response,String fileName,String downLoadPath,String contentType) throws IOException{
        response.setContentType("text/html;charset=UTF-8");
        request.setCharacterEncoding("UTF-8");
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;    
        long fileLength = new File(downLoadPath).length();
        response.setContentType(contentType);
        response.setHeader("Content-disposition", "attachment; filename=" + new String(fileName.getBytes("utf-8"), "ISO8859-1"));
        response.setHeader("Content-Length", String.valueOf(fileLength));
        bis = new BufferedInputStream(new FileInputStream(downLoadPath));
        bos = new BufferedOutputStream(response.getOutputStream());
        byte[] buff = new byte[2048];
        int bytesRead;
        while(-1 != (bytesRead = bis.read(buff, 0, buff.length))){
            bos.write(buff, 0, bytesRead);
        }
        bis.close();
        bos.close();
    }
//第二个工具类中的主要关键代码:
    String filename = null;
    if(request.getHeader("User-Agent").toUpperCase().indexOf("MSIE") > 0){
        filename = URLEncoder.encode(name, "UTF-8");
    }else{
        filename = new String(name.getBytes(),"ISO8859-1");
    }
    response.setHeader("Content-Disposition", "attachment;filename=" + filename);


为了知道这样子到底会有什么问题,是不是只有IE会出现问题,其他浏览器会不会有其他的问题。抱着这些疑问,我找来了目前市面上用户量较多的几款主流的浏览器进行测试,包括:两个不同版本的IE11,Chrome,FireFox,Opera,360浏览器,搜狗浏览器等。经过我对下载的文件的各种文件名称使劲地折腾主要发现以下几个问题:

1.两个IE11在使用第一个方法下载文件时中文文件名都会乱码,而使用第二个方法下载时其中一个IE11中文不会乱码,另一个IE11则会乱码;

2.文件名中存在空格时两个IE11浏览器下载下来文件文件名空格会变成+号,其他浏览器没有这个问题;

3.火狐浏览器下载时遇到文件名中有空格时下载下来的文件的文件名第一个空格后面的文字都会丢失。

经过一番折腾发现原来我们大国产浏览器还是可以的,没有发现明显的问题;233333。

那么这些问题该如何解决呢?首先第一个问题,显然第一段代码并没有将IE浏览器过滤出来对文件名进行单独编码,而是统一采用ISO8859-1编码,这样如果文件名是英文的IE就不会出现任何问题,中文就会出现乱码,其他语言文字则不清楚,其他几款浏览器则没有任何问题,都能兼容。那第二段代码则首先对Http请求头中User-Agent参数进行了判断,通过MISE字段将IE浏览器过滤出来,对文件名进行单独UTF-8编码,所以中文文件名不会乱码了。那么问题来了,为什么两个IE11浏览器,其中一个中文不乱码,而另一个却乱码呢。经过对程序的单步调试,发现那个中文乱码的IE在进入这个方法后程序并没有跳入对文件名进行utf-8编码的方法,而是进入了else下面的那一行代码。那也就是说两个IE11的User-Agent参数中,其中一个有MISE关键字,而另一个则没有。通过查阅资料,原来微软在IE11之后在浏览器的User-Agent参数中去掉了MISE关键字,导致的结果是使用低版本的IE下载中文文件名文件时不会乱码,而采用大部分IE11及以上版本,包括Edge等都会出现中文乱码现象。难怪大家老是说IE很坑呢,IE在这种地方都埋好了坑,等着我们去踩,我也是醉了。

浏览器的User-Agent这个参数主要包含了一些操作系统版本,浏览器版本、内核等信息。

那个下载文件中文会乱码的IE的User-Agent参数如下:

IE11:Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko;

显然里面并没有MISE关键字,那么怎么办呢?通过对比几款不同浏览器的User-Agent参数,发现这里面有一个Trident关键字比较特别,是其他浏览器所没有的,那么解决方案来了,我们可以通过Trident关键字来进行对部分IE11的过滤了;

那么针对第二个问题中出现的空格变+号,则是因为URLEncoder函数在对字符串进行转码后将空格替换成了+号,IE就直接把+号显示出来了,解决方法是在对文件名进行转码后,使用replace方法将+号替换为%20即可,浏览器会将%20转换成空格输出。

对于第三个问题则是因为代码在set响应头时Content-Disposition参数的attachment;filename=等号后面文件名字符串没有用双引号括起来,火狐浏览器对于遇到文件名有空格时认为空格前的字符是一个完整的字符串,故下载下来文件时文件名就只剩下空格前的那几个字了。解决方法是在filename两边加上双引号并加反斜杠转义。具体的最终解决这些问题后经过测试兼容性比较好的代码如下:

public static void download(HttpServletRequest request, HttpServletResponse response, String fileName, String downLoadPath, String contenType) throws Exception {
        response.setContentType("text/html;charset=UTF-8");
        request.setCharacterEncoding("UTF-8");
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;
        long fileLength = new File(downLoadPath).length();
        response.setContentType(contenType);
        String header = request.getHeader("User-Agent").toUpperCase();
        if (header.contains("MSIE") || header.contains("TRIDENT") || header.contains("EDGE")) {
            fileName = URLEncoder.encode(fileName, "utf-8");
            fileName = fileName.replace("+", "%20");    //IE下载文件名空格变+号问题
        } else {
            fileName = new String(fileName.getBytes(), "ISO8859-1");
        }
        response.setHeader("Content-disposition", "attachment; filename=\"" + fileName + "\"");
        response.setHeader("Content-Length", String.valueOf(fileLength));
        bis = new BufferedInputStream(new FileInputStream(downLoadPath));
        bos = new BufferedOutputStream(response.getOutputStream());
        byte[] buff = new byte[2048];
        int bytesRead;
        while (-1 != (bytesRead = bis.read(buff, 0, buff.length))) {
            bos.write(buff, 0, bytesRead);
        }
        bis.close();
        bos.close();
    }

或者,使用下面这段代码也可以处理乱问题,代码如下:

try {
       String fileName = attachmentFile.originalName();
       String userAgent = request.getHeader("user-agent").toLowerCase();  
       if (userAgent.contains("msie") || userAgent.contains("like gecko") ) {  
            // win10 ie edge 浏览器 和其他系统的ie  
            fileName = URLEncoder.encode(fileName, "UTF-8");  
       } else {  
            //其他的浏览器
            fileName = new String(fileName.getBytes("utf-8"), "iso-8859-1");  
       }  
       response.setCharacterEncoding("utf-8");
       response.setContentType("multipart/form-data");
       response.setHeader("Content-Disposition", "attachment;fileName=" + fileName);
       String path = attachmentFile.path();
       InputStream inputStream = new FileInputStream(new File(path));
       OutputStream os = response.getOutputStream();
       byte[] b = new byte[2048];
       int length;
       while ((length = inputStream.read(b)) > 0) {
           os.write(b, 0, length);
       }
         // 这里主要关闭流。
          os.close();
          inputStream.close();
    } catch (FileNotFoundException e) {
          e.printStackTrace();
    } catch (IOException e) {
          e.printStackTrace();
    }
目录
相关文章
|
2月前
|
Web App开发 JavaScript 前端开发
添加浮动按钮点击滚动到网页底部的纯JavaScript演示代码 IE9、11,Maxthon 1.6.7,Firefox30、31,360极速浏览器7.5.3.308下测试正常
添加浮动按钮点击滚动到网页底部的纯JavaScript演示代码 IE9、11,Maxthon 1.6.7,Firefox30、31,360极速浏览器7.5.3.308下测试正常
|
3月前
|
XML 缓存 JSON
为什么浏览器中有些图片、PDF等文件点击后有些是预览,有些是下载
为什么浏览器中有些图片、PDF等文件点击后有些是预览,有些是下载
257 0
|
9天前
|
Web App开发 缓存 安全
WIN11 Chrome 双击打不开闪退及Chrome浏览器不能拖拽文件crx
【11月更文挑战第6天】本文介绍了 WIN11 系统中 Chrome 浏览器双击打不开闪退及不能拖拽文件 crx 的原因和解决方法。包括浏览器版本过旧、扩展程序冲突、硬件加速问题、缓存过多、安全软件冲突、系统文件损坏、用户配置文件损坏等问题的解决方案,以及 crx 文件的屏蔽、权限问题和文件格式问题的处理方法。
|
23天前
|
Web App开发 Java
使用java操作浏览器的工具selenium-java和webdriver下载地址
【10月更文挑战第12天】Selenium-java依赖包用于自动化Web测试,版本为3.141.59。ChromeDriver和EdgeDriver分别用于控制Chrome和Edge浏览器,需确保版本与浏览器匹配。示例代码展示了如何使用Selenium-java模拟登录CSDN,包括设置驱动路径、添加Cookies和获取页面源码。
|
1月前
|
JavaScript 前端开发
|
2月前
|
JSON 前端开发 JavaScript
java中post请求调用下载文件接口浏览器未弹窗而是返回一堆json,为啥
客户端调接口需要返回另存为弹窗,下载文件,但是遇到的问题是接口调用成功且不报错,浏览器F12查看居然返回一堆json,而没有另存为弹窗; > 正确的效果应该是:接口调用成功且浏览器F12不返回任何json,而是弹窗另存为窗口,直接保存文件即可。
141 2
|
3月前
|
Web App开发 JSON 数据格式
【Azure Developer】浏览器查看本地数据文件时遇见跨域问题(CORS)
【Azure Developer】浏览器查看本地数据文件时遇见跨域问题(CORS)
【Azure Developer】浏览器查看本地数据文件时遇见跨域问题(CORS)
|
3月前
|
JavaScript
VUE——如何兼容IE9|IE10|IE11浏览器
VUE——如何兼容IE9|IE10|IE11浏览器
134 0
VUE——如何兼容IE9|IE10|IE11浏览器
|
4月前
|
安全 网络安全
用IE浏览器访问网站提示证书错误
当你在Internet Explorer中遇到证书错误提示,通常是因网站SSL/TLS证书问题或浏览器安全设置需调整。解决方法包括: 检查时间设置 调整IE设置 安装证书 调整计算机时间
111 3
|
3月前
|
存储 NoSQL 文件存储
【Azure 环境】存储在Azure上的文件,使用IE/Edge时自动打开的问题,如何变为下载而非自动打开
【Azure 环境】存储在Azure上的文件,使用IE/Edge时自动打开的问题,如何变为下载而非自动打开