手机txt文件打开乱码修复方法 txt文档乱码怎么修复

Web 开发过程中,相信大家都遇到过附件下载的场景,其中,各浏览器下载后的文件名中文乱码问题或许一度让你苦恼不已 。
网上搜索一下,大部分都是通过Request Headers中的UserAgent字段来判断浏览器类型,根据不同的浏览器做不同的处理,类似下面的代码:
// MicroSoft Browserif (agent.contains("msie") || agent.contains("trident") || agent.contains("edge")) {// filename 特殊处理}// firefoxelse if (agent.contains("firefox")) {// filename 特殊处理}// safarielse if (agent.contains("safari")) {// filename 特殊处理}// Chromeelse if (agent.contains("chrome")) {// filename 特殊处理}// 其他else{ // filename 特殊处理}//最后把特殊处理后的文件名放到head里response.setHeader("Content-Disposition","attachment;fileName=" + filename);不过,这样的代码看起来很魔幻,为什么每个浏览器的处理方式都不一样?难道每次新出一个浏览器都要做兼容吗?就没有一个统一标准来约束一下这帮浏览器吗?
带着这个疑惑,我翻阅了 RFC 文档,最终得出了一个优雅的解决方案:
// percentEncodedFileName 为百分号编码后的文件名response.setHeader("Content-disposition","attachment;filename=" + percentEncodedFileName +";filename*=utf-8''" + percentEncodedFileName);经过测试,这段响应头可以兼容市面上所有主流浏览器,由于是 HTTP 协议范畴,所以语言无关 。只要按这个规则设置响应头,就能一劳永逸地解决恼人的附件名中文乱码问题 。
接下来课代表带大家抽丝剥茧,通过阅读 RFC 文档,还原一下这个响应头的产出过程 。
1. Content-Disposition一切要从 RFC 6266 开始,在这份文档中,介绍了Content-Disposition响应头,其实它并不属于HTTP标准,但是因为使用广泛,所以在该文档中进行了约束 。它的语法格式如下:
content-disposition = "Content-Disposition" ":"disposition-type *( ";" disposition-parm )disposition-type= "inline" | "attachment" | disp-ext-type; case-insensitivedisp-ext-type= tokendisposition-parm= filename-parm | disp-ext-parmfilename-parm= "filename" "=" value| "filename*" "=" ext-value其中的disposition-type有两种:

  • inline 代表默认处理,一般会在页面展示
  • attachment 代表应该被保存到本地,需要配合设置filename或filename*
注意到disposition-parm中的filename和filename*,文档规定:这里的信息可以用于保存的文件名 。
它俩的区别在于,filename 的 value 不进行编码,而filename*遵从 RFC 5987中定义的编码规则:
Producers MUST use either the "UTF-8" ([RFC3629]) or the "ISO-8859-1" ([ISO-8859-1]) character set.由于filename*是后来才定义的,许多老的浏览器并不支持,所以文档规定,当二者同时出现在头字段中时,需要采用filename*,忽略filename 。
至此,响应头的骨架已经呼之欲出了,摘录 [RFC 6266] 中的示例如下:
Content-Disposition: attachment;filename="EURO rates";filename*=utf-8''%e2%82%ac%20rates这里对filename*=utf-8”%e2%82%ac%20rates做一下说明,这个写法乍一看可能会觉得很奇怪,它其实是用单引号作为分隔符,将等号右边分成了三部分:第一部分是字符集(utf-8),中间部分是语言(未填写),最后的%e2%82%ac%20rates代表了实际值 。对于这部分的组成,在RFC 2231.section 4 中有详细说明:
A single quote is used toseparate the character set, language, and actual value information inthe parameter value string, and an percent sign is used to flagoctets encoded in hexadecimal.2.PercentEncodePercentEncode 又叫 Percent-encoding 或 URL encoding.
正如前文所述,filename*遵守的是[RFC 5987] 中定义的编码规则,在[RFC 5987] 3.2中定义了必须支持的字符集:
recipients implementing this specificationMUST support the character sets "ISO-8859-1" and "UTF-8".并且在[RFC 5987] 3.2.1规定,百分号编码遵从 RFC 3986.section 2.1中的定义,摘录如下:
A percent-encoding mechanism is used to represent a data octet in acomponent when that octet's corresponding character is outside theallowed set or is being used as a delimiter of, or within, thecomponent.A percent-encoded octet is encoded as a charactertriplet, consisting of the percent character "%" followed by the twohexadecimal digits representing that octet's numeric value.Forexample, "%20" is the percent-encoding for the binary octet"00100000" (ABNF: %x20), which in US-ASCII corresponds to the spacecharacter (SP).Section 2.4 describes when percent-encoding anddecoding is applied.注意了,[RFC 3986] 明确规定了空格 会被百分号编码为%20
而在另一份文档 RFC 1866.Section 8.2.1

    推荐阅读