接口调用中BOM头带来的问题

经验往往是伴随着“惨痛”的教训而来,比如说最近的这次。事情的起因,源于最近的一次上线:手机客户端的“微博视频广场”代码修改上线后,页面突然异常,模块展示各种混乱,整个视频广场都变得“不好了”。。。

1.查找bug原因

    有了问题就要查找原因。首先想到的是调用接口返回的数据异常。但是手动调用接口(浏览器调用&终端curl调用),返回的json格式数据都是正确的,接口输出“看起来”没有问题。

    无奈之下,只得求助于接口调用方,经过不断的打断点调试,终于在接口输出json数据的开头,发现了诡异的“\ufeff”字符(见下图)!!!而恰恰由于这几个字符,导致了接口输出的json串解析失败!

    马上百度之,发现返回结果中都提到了“BOM头”!原来是BOM头捣的鬼!bug的原因终于找到了!

    也许看到这,你不禁想问什么是BOM头?不要急,下面就跟大家介绍下~

2.php与BOM头

    BOM(Byte Order Mark)是一个字节顺序标签,类似一个标记,又叫签名,用来告诉编辑器当前文件采用何种编码,方便编辑器识别。除了unicode编码,一般的编码集并不会出现bom头。对于utf-16和utf-32,如果不指定bom头,解析程序就默认为ansi编码,从而出现乱码;而对于utf-8,BOM头指定与否,解析程序都可判断。

    现在几乎所有的文本编辑软件都可以显示并编辑UTF-8编码的文件,但其中很多的表现并不理想。类似WINDOWS自带的记事本等软件,在保存一个以UTF-8编码的文件时,会在文件开始的地方插入三个不可见的字符0xEF、0xBB和0xBF,即BOM。对于一般的文件,这样做并不会产生麻烦。但对于 PHP来说,BOM是个大麻烦。因为PHP并不会忽略BOM,所以在读取、包含或者引用这些文件时,会把BOM作为该文件开头正文的一部分。同时根据嵌入式语言的特点,这串字符最终将被直接执行(显示)出来。

    回到我们的问题中,由于有个配置文件在开发时用WINDOWS自带的记事本编辑保存过,导致这个文件在开头加入了BOM头,而这个配置文件在各个php接口脚本中都被读取过,从而导致接口输出的json格式数据前面多了BOM头。

3.bug解决办法

    找到了问题原因,解决方法就很简单了:把utf-8编码文件的BOM头去掉。可以编写程序,检测文件头的三个字符是否为0xEF、0xBB和0xBF,如果是的话,直接删除掉即可;也可以用下文提到的靠谱的编辑器,打开文件重新编辑,设置为无BOM头的utf-8编码。例如Notepad++的使用如下图:



4.经验总结

    写到这里回头看,其实问题的原因很简单,但却很隐蔽,导致排查问题、查找原因的过程十分痛苦纠结。事后我也在不断思考,试图去总结些普遍试用的经验教训,以避免同类问题的再次发生。以下是一点浅见。

    最最重要的教训,就是不要忽略测试!这里说的测试,不是自己开发完自己测,而是由QA,在上线前执行标准化的测试流程!这也是避免非环境原因导致隐蔽bug的有效措施之一!

    其次,就是上线前通过svn合代码进行code review时,不忽视任何细小的改动。BOM头是在文件开头添加了3个字符,在新旧代码的对比中,其实这种改动svn也会检测出来;但限于svn编辑器无法显示BOM头,直观的看,文件的开头好像多了个空格,但实际什么都没有。遇到这种情况,很大可能性就是BOM头捣的鬼!

    此外,在编辑、更改任何文本文件时,不要使用乱加BOM的编辑器!尤其是WINDOWS下,不要使用记事本做编辑器!!!

推荐几个靠谱的编辑器:Editplus,Notepad++,EmEditor,UltraEdit,Dreamweaver(需要取消‘添加BOM’的相关选项)等。

5.BOM头对php程序的其他危害

    BOM头对php程序的危害,最典型、最严重的,还不是上文提到的情况。如果在涉及到COOKIE实现的php文件中有BOM头,由于在COOKIE送出前PHP已经送出了文件头,那么受COOKIE送出机制的限制,COOKIE将无法送出,导致登入和登出功能失效!一切依赖COOKIE、SESSION实现的功能都将无效!

    另外一个典型危害:如果php程序实现xml格式的数据输出,并且php文件有BOM头,那么会造成输出的xml格式数据解析失败!

 

转自:http://weibo.com/p/1001603783734905204405

2 comments:

评论已关闭。