最近,在公司的某个项目中,测试人员发现了一个颇有意思的Bug。当用户的我的资料页面的邮箱联系方式是中文后缀时,例如"mi@测试.com",在Android原平生台上会显示乱码的现象,而在浏览器中显示则正常,结果以下面两张图所示。在另外一个同事寻找资料无果的状况下,因而,我开始了一步步分析这个问题的过程。
上图是Android设备
上图是浏览器中
html
由于两个环境中调用的都是同一个接口返回的数据,因此以我的多年的工做经验来看,这个问题多是编码方面的问题。因而,我列出了如下几种状况:浏览器
针对以上的几种状况,我分别询问了各位同事和抓包看返回的数据,发现:一、Web端、服务器端都没有进行转码操做。二、在出现乱码的Android端,拿到的数据就是接口返回的原始数据。并且,我也尝试过对几种常见的编码进行转换操做,看看能不能找到问题所在,可是都不是我想要的结果。那,问题究竟在哪?
服务器
在初次分析无果的状况下,我开始考虑会不会是由于Web端的使用的第三方框架的缘由。由于Web端使用了Element UI,有没有可能Element UI对<input />标签进行了二次封装,并进行了转码操做?同时,经Web端的同事提醒,<input />标签的type属性为"email"。因而,我决定,我直接新建了一个新的HTML文件,为了避免受其它影响,里面就只有一个<input />标签。
框架
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <input type="email" /> </body> </html>
而后,在Chrome 浏览器中打开,输入测试字段"mi@测试.com"。结果显示一切正常,中文依然正确显示,彷佛没有任何问题。可是本着要打破砂锅问到底的精神,我试着在浏览器中改了一下标签的type值,我尝试着将"email"改为"text"。没想到,问题复现了。
https://www.bilibili.com/vide...ide
将type="email"改为type="text"之后,浏览器中中文部分会出现乱码,而再改回去之后,显示又一切正常。另外一方面,我试着在在Chrome控制台中获取input值,看看原始值究竟是什么。结果,也有了惊奇的发现。 此时input标签的type值依然是"email",但在控制台中打印出来的结果竟然是乱码的字符串,如今看来,问题的关键点颇有可能就是在这个type="email"上!
测试
有过Web开发的同窗们应该对这个属性是很熟悉的了,至于type的其它类型,就不在本文中阐述了,咱们直接看MDN上关于<input type="email">的相关资料,试着去了解一下,当type="email"的时候,浏览器究竟作了什么?(更多细节能够点击这个连接进行查看)。网站
带有 "email" (电子邮箱)类型标记的输入框元素()可以让用户输入或编辑一个电子邮箱地址,此外,若是指定了multiple属性,用户还能够输入多个电子邮箱地址。在表单提交前,输入框会自动验证输入值是不是一个或多个合法的电子邮箱地址(非空值且符合电子邮箱地址格式). CSS伪标签 :valid 和 :invalid 可以在校验后自动应用。
根据引用MDN网站上的文字的描述,个人一个猜测是,多是浏览器在作验证的时候进行了转码操做,同时,我又看到网页中的这个相关描述。而后,我点击了DOMString来进行更深刻的了解。搜索引擎
DOMString 是一个UTF-16字符串。因为JavaScript已经使用了这样的字符串,因此DOMString 直接映射到 一个String
看到这两个描述,我第一反应是,难道"mix@测试.com"是被转码成了UTF-16?可是,转码后的字符串并非常见的UTF-16的格式。因此直觉告诉我,事情没有那么简单,这不是我想要的结果。因而我继续在当前的MDN网页上查看相关资料,在网页的下端,一段内容引发了个人注意。引发我注意的不只仅是那段正则,还有下面的提示--W3C bug 15489。
打开连接后我发现W3C bug 15489 是2012年由一位叫 Mathias Bynens 外国工程师 提出来的问题,在这个讨论问题的帖子的页面中,我惊喜的发现,这个网页中所提的bug正是我苦苦寻找的问题所在。
顺着这个结果,我发现关键的线索--Punycode!我立马打开的新的网页,找一个在线Punycode编码的网站。BingGo!
编码
那么,问题的因此在看来就是这个Punycode了,那什么是Punycode呢?引用百度百科的里的解释:spa
Punycode(译为:域名代码)是一种表示Unicode码和ASCII码的有限的字符集。例如:“münchen”(德国慕尼黑)会被编码为“mnchen-3ya”。
同时,了解到一个新的知识点--IDNs(国际化域名 Internationalized Domain Names)。早期的DNS是只支持英文域名解析。在IDNs推出之后,为了保证兼容之前的DNS,因此,对IDNs进行Punycode转码,转码后的Punycode就由26个字母+10个数字,还有“-”组成。
顺着这个,我接着往下看,这个页面里发现了一个更有意思和详细的资料。
因此,通过几乎1个小时的时间,通过各类资料的汇总,这个问题终于被摸清楚了。
在浏览器中type属性为email的input标签能正常显示中文后缀的缘由,是由于现代浏览器自动加入中文域名的转码。正如上文所说,是浏览器软件里面主动加入了中文域名自动转码,因此中文后缀才会显示正常。同时,这也就解释了为何在type="email"的状况下。浏览器控制台中获取的value会依然是乱码后的字符串。那么,既然知道问题的所在,解决的方法天然也很简单了,经过搜索引擎或者本身写一个关于Punycode转码的方法应该就能将问题顺利解决了。