佛系的发发 2025-01-21 17:33 采纳率: 100%
浏览 12
已结题

浏览器编码乱码转换处理

window.open下载文件,是如何准确的获取到中文文件名的呢?

我在做一些很老旧的功能改造,项目中用到了很多window.open 下载文件的方式;由于我需要捕获且展示下载接口有可能返回的错误信息,所以我不再使用window.open下载,而是在ajax.get回调中处理;
回调中需要获得响应头中的Content-Disposition字段读取文件名【文件名包含中文】 ,但获取到的总是乱码,图如:

1、

img

2、

img

经过尝试,发现有部分filename 原来是gbk | utf-8编码,因为reponse Header 只能使用iso-8859-1的缘故,转成了不同的看似乱码的情况,得经过转换才能还原到原来的中文,操作:

            // 默认原来以gbk方式解码
            let codeType = 'gbk';
            if(contentType === 'application/x-msdownload'){
              codeType = 'utf-8'
            }
            const contentDisposition = xhr.getResponseHeader('Content-Disposition');
            const filename = contentDisposition.split('filename=')[1].replace(/"/g, '');
            // 将 ISO-8859-1 编码的 filename 转换回 GBK或者utf-8
            const byteCharacters = new Uint8Array(filename.split('').map(c => c.charCodeAt(0)));
            const decoder = new TextDecoder(codeType);
            // 解码回中文的下载文件名
            const decodedFilename = decoder.decode(byteCharacters);


          // 下载文件
           const blob = new Blob([xhr.response], { type: xhr.getResponseHeader('Content-type') });
            const link = document.createElement('a');
          // 使用 blob 作为 URL  
            link.href = window.URL.createObjectURL(blob); 
            // 设置下载文件名
            link.download = window.decodeURIComponent(decodedFilename) || '导出文件'; 
            link.click();

目前适配了系统多数文件的下载;但是不知道window.open是做了什么操作,下载的文件名称总能很好的转成对应的中文?我上面那种方案,有挺大的风险,假如原来的编码是utf-8,而我使用gbk 去decode的话就也会乱码。
请教各位,能否给一些资料参考或者建议,比如window.open之后浏览器的下载操作【浏览器层面是怎么识别到filename并转换为中文】,又比如当前是乱码的情况下,怎么判断经iso-8859-1转化前,原来的编码格式是gbk 还是 utf-8?

  • 写回答

2条回答 默认 最新

  • GISer Liu 2025-01-21 23:52
    关注

    该回答引用自GPT-deepseek, 由博主 GISer Liu 编写:

    问题分析

    用户在通过 window.open 下载文件时,能够正确获取并显示中文文件名,但在使用 ajax.get 回调处理下载时,获取到的 Content-Disposition 字段中的中文文件名出现乱码。用户尝试通过手动解码来解决这个问题,但存在编码格式不确定性的风险。

    关键点

    1. window.open 下载文件的机制window.open 是通过浏览器直接处理下载请求,浏览器会自动处理响应头中的 Content-Disposition 字段,并根据浏览器的默认编码或服务器指定的编码来正确显示中文文件名。

    2. ajax.get 回调处理下载的问题:在使用 ajax.get 时,浏览器不会自动处理 Content-Disposition 字段中的编码问题,导致中文文件名出现乱码。

    3. 编码问题Content-Disposition 字段中的文件名可能使用不同的编码(如 GBKUTF-8),但响应头只能使用 ISO-8859-1 编码,因此需要手动解码。

    解决方案

    1. 自动检测编码格式

    为了自动检测 Content-Disposition 字段中的文件名编码格式,可以使用 chardetjschardet 等库来检测编码格式。这样可以避免手动指定编码格式的风险。

    2. 使用 fetch API 替代 ajax.get

    fetch API 提供了更强大的功能来处理响应头,并且可以通过 Response 对象的 headers 属性直接获取 Content-Disposition 字段。

    3. 解码文件名

    在获取到 Content-Disposition 字段后,使用 TextDecoder 进行解码,并根据检测到的编码格式进行解码。

    代码实现

    import { detect } from 'jschardet';
    
    function downloadFile(url) {
      fetch(url)
        .then(response => {
          const contentDisposition = response.headers.get('Content-Disposition');
          const contentType = response.headers.get('Content-Type');
          const filenameMatch = contentDisposition.match(/filename\*?=(?:UTF-8'')?"?([^"]+)"?/i);
    
          let filename = filenameMatch ? filenameMatch[1] : '导出文件';
    
          // 检测编码格式
          const detectedEncoding = detect(filename).encoding;
    
          // 解码文件名
          const decoder = new TextDecoder(detectedEncoding);
          const byteCharacters = new Uint8Array(filename.split('').map(c => c.charCodeAt(0)));
          const decodedFilename = decoder.decode(byteCharacters);
    
          return response.blob().then(blob => {
            const link = document.createElement('a');
            link.href = window.URL.createObjectURL(blob);
            link.download = window.decodeURIComponent(decodedFilename);
            link.click();
          });
        })
        .catch(error => {
          console.error('下载文件时出错:', error);
        });
    }
    
    // 使用示例
    downloadFile('https://example.com/path/to/file');
    

    解释

    1. fetch API:使用 fetch API 替代 ajax.get,以便更好地处理响应头。

    2. jschardet:使用 jschardet 库检测 Content-Disposition 字段中的文件名编码格式。

    3. **TextDecoder**:根据检测到的编码格式,使用 TextDecoder 解码文件名。

    4. blob 下载:将响应数据转换为 blob,并通过创建 <a> 标签触发下载。

    参考资料

    通过上述方案,可以有效地解决 ajax.get 回调处理下载时中文文件名乱码的问题,并且避免了手动指定编码格式的风险。

    如果该回答解决了您的问题,请采纳!如果没有,请私信联系或评论您的疑惑

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

问题事件

  • 系统已结题 1月30日
  • 已采纳回答 1月22日
  • 创建了问题 1月21日