浏览器端JS通过DataURI创建下载UTF-8纯文本文件编码异常问题
问题根因
btoa() 方法仅支持将 Latin1编码(即ISO-8859-1,单字节字符集) 的字符串转换为Base64格式。你直接传入包含UTF-8多字节字符的字符串时,btoa() 会自动将每个字符截断为单字节的Latin1编码,最终输出的Base64内容本身就是Latin1编码的,和Data URI头声明的charset没有关联,所以下载后的文件编码自然是错误的。
修复方案
方案1:使用TextEncoder转换(现代浏览器兼容,推荐)
先通过TextEncoder将JS原生字符串转为UTF-8字节数组,再转换为Base64即可保证编码正确:
const myText = "àòùè"; // 转换为UTF-8字节数组 const utf8Bytes = new TextEncoder().encode(myText); // 字节数组转Base64字符串 const base64 = btoa(String.fromCharCode(...utf8Bytes)); const uriContent = "data:text/plain;charset=utf-8;base64," + base64; const element = document.createElement('a'); element.setAttribute('href', uriContent); element.setAttribute('download', "example_filename.log"); element.style.display = 'none'; document.body.appendChild(element); element.click(); document.body.removeChild(element);
方案2:老旧浏览器兼容方案
如果需要兼容不支持TextEncoder的低版本浏览器,可以用encodeURIComponent+unescape的组合先将字符串转成UTF-8编码的单字节序列,再做Base64转换:
const myText = "àòùè"; const base64 = btoa(unescape(encodeURIComponent(myText))); const uriContent = "data:text/plain;charset=utf-8;base64," + base64; // 后续下载逻辑和之前一致
可选优化:使用Blob生成下载链接
相比Data URI,用Blob生成下载链接的编码处理更简单,也没有Base64转换的额外开销,更推荐日常使用:
const myText = "àòùè"; // 直接生成UTF-8编码的文本Blob const blob = new Blob([myText], { type: 'text/plain;charset=utf-8' }); const uriContent = URL.createObjectURL(blob); const element = document.createElement('a'); element.setAttribute('href', uriContent); element.setAttribute('download', "example_filename.log"); element.style.display = 'none'; document.body.appendChild(element); element.click(); document.body.removeChild(element); // 用完释放Object URL,避免内存泄漏 URL.revokeObjectURL(uriContent);
修复完成后再用file命令校验,就能得到正确的UTF-8编码结果:
file example_filename.log example_filename.log: UTF-8 Unicode text
内容的提问来源于stack exchange,提问作者MadPapo
相关产品推荐
相关产品推荐

