广州linux

当前位置:   网站首页 >> 网络杂谈

BOM引发的json传输错误

今天调试php生成json,发现老是出错于是有了下文:

返回了400,输出了json,发现明明是200,可是为什么会返回400呢
图片

检查php文件,看到编码是utf8,想想应该不会出错,于是多次修改代码,发现问题还是没有解决,于是检查之前没有问题的php文件
图片
突然发现有bom 百度了一下,知道UTF-8 BOM又叫UTF-8 签名,其实UTF-8 的BOM对UFT-8没有作用,是为了支持UTF-16,UTF-32才加上的,果断修改文件编码类型,成功返回200,下面是百度对bom的介绍

-----------------------------------------------------------------



------------------------------------------------------------------------------------------------

写python脚本的时候发现这样一个问题:从xls文件导出到txt时,无法直接转换为int型数据,输出查看发现和文件编码方式产生的附加信息有关用一个简单的文件举例

 

90905

 

90907

 

90908

 

90909

 

90939

 

90940

 

90946

 

90959

 

90961

 

90965

 

当文件分别用ascii,utf8,utf8+bom作为编码格式时,显示输出结果如下:

 

使用ascii编码的输出:

 

['90905\r\n', '90907\r\n', '90908\r\n', '90909\r\n', '90939\r\n', '90940\r\n', '90946\r\n', '90959\r\n', '90961\r\n', '90965']

 

使用utf8编码的输出:

 

['90905\r\n', '90907\r\n', '90908\r\n', '90909\r\n', '90939\r\n', '90940\r\n', '90946\r\n', '90959\r\n', '90961\r\n', '90965']

 

使用bom编码的输出:

 

['\xef\xbb\xbf90905\r\n', '90907\r\n', '90908\r\n', '90909\r\n', '90939\r\n', '90940\r\n', '90946\r\n', '90959\r\n', '90961\r\n', '90965']

 

原来utf8+bom不能直接转换int的原因在这里,它在文件头插入了一个表示文件编码的信息\xef\xbb\xbf,那么UTF-8(无BOM)和UTF-8这两个有什么区别呢?BOM是什么呢?

 
什么是BOM?

 
BOM: Byte Order Mark

 

UTF-8 BOM又叫UTF-8 签名,其实UTF-8 的BOM对UFT-8没有作用,是为了支持UTF-16,UTF-32才加上的

 

BOM,BOM签名的意思就是告诉编辑器当前文件采用何种编码,方便编辑器识别,但是BOM虽然在编辑器中不显示,但是会产生输出,就像多了一个空行。

 

Byte Order Marks are special characters at the beginning of a Unicode file to indicate whether it is big or little endian, in other words does the high or low order byte come first. These codes also tell whether the encoding is 8, 16 or 32 bit. You can recognise Unicode files by their starting byte order marks, and by the way Unicode-16 files are half zeroes and Unicode-32 files are three-quarters zeros. Unicode Endian Markers

 

Byte-order mark Description  
EF BB BF UTF-8    
FF FE UTF-16 aka UCS-2, little endian    
FE FF UTF-16 aka UCS-2, big endian    
00 00 FF FE UTF-32 aka UCS-4, little endian.    
00 00 FE FF UTF-32 aka UCS-4, big-endian.

 
UTF的字节序和BOM

 

UTF- 8以字节为编码单元,没有字节序的问题。UTF-16以两个字节为编码单元,在解释一个UTF-16文本前,首先要弄清楚每个编码单元的字节序。例如收到 一个“奎”的Unicode编码是594E,“乙”的Unicode编码是4E59。如果我们收到UTF-16字节流“594E”,那么这是“奎”还是 “乙”?

 

Unicode规范中推荐的标记字节顺序的方法是BOM。BOM不是“Bill Of Material”的BOM表,而是Byte Order Mark。BOM是一个有点小聪明的想法:

 

在 UCS编码中有一个叫做"ZERO WIDTH NO-BREAK SPACE"的字符,它的编码是FEFF。而FFFE在UCS中是不存在的字符,所以不应该出现在实际传输中。UCS规范建议我们在传输字节流前,先传输 字符"ZERO WIDTH NO-BREAK SPACE"。

 

这样如果接收者收到FEFF,就表明这个字节流是Big-Endian的;如果收到FFFE,就表明这个字节流是Little-Endian的。因此字符"ZERO WIDTH NO-BREAK SPACE"又被称作BOM。

 

UTF-8不需要BOM来表明字节顺序,但可以用BOM来表明编码方式。字符"ZERO WIDTH NO-BREAK SPACE"的UTF-8编码是EF BB BF。所以如果接收者收到以EF BB BF开头的字节流,就知道这是UTF-8编码了。

 

Windows就是使用BOM来标记文本文件的编码方式的。

 

原来BOM是在文件的开始加了几个字节作为标记。有了这个标记,一些协议和系统才能识别。

 

ok,说了这么多背景,那么如何解决这个问题呢?

 
如何使用BOM头

 
BOM头的删除

 

对UTF-16, Python将BOM解码为空字串。然而对UTF-8, BOM被解码为一个字符,如例:

 >>> codecs.BOM_UTF16.decode( "utf16" )  u''  >>> codecs.BOM_UTF8.decode( "utf8" )  u'\ufeff'

简单的做法是在文件读入时使用

import codecsf = codecs.open(sys.argv[1],'r', 'utf_8_sig')

即 可,具体可以参见[http://docs.python.org/library/codecs.html#module- encodings.utf_8_sig|http://docs.python.org/library/codecs.html#module-encodings.utf_8_sig]

或者:

u.lstrip( unicode( codecs.BOM_UTF8, "utf8" ) )
BOM头的添加

out = file( "someFile", "w" )out.write( codecs.BOM_UTF8 )out.write( unicodeString.encode( "utf-8" ) )out.close()out = file( "someFile", "w" )out.write( codecs.BOM_UTF8 )out.write( unicodeString.encode( "utf-8" ) )out.close()

发表我的评论

Hi,您需要填写昵称和邮箱!

  • 必填项