web开发编码问题

关于在web开发过程中的编码问题


前言

昨天小编写的一个小的表单提交程序发现了乱码的问题,虽说以前也碰到过,而且这次解决起来也挺快,但是也一直没有认真的去想过这个问题,究竟从表单提交到服务器端响应请求这中间的编码机制到底是怎样?

先抛几个问题:

  • 为什么有时候<meta charset="utf-8">不太管用?
  • html页面的编码方式究竟由什么决定?
  • 各浏览器对编码的处理一样吗?

更改html页面编码

因为小编百度了无数遍后感觉答案很多,不够统一,各有各的说法。所以直接上W3C官网去查看相关的标准和文档。下面的内容大多来自于W3C官网和小编自己的测试。

英文好的同学可以直接看W3C文档:W3C文档

回归正题,指定网页的编码如下代码:

<html>
    <head>
        <meta charset="utf-8">
        ...
    </head>
...
</html>

上面的代码应该人人都知道把,但是好像有时候并不是什么时候都管用,至于为什么等一下会说。

还有第二种方式就是:

<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
        ...
    </head>
...
</html>

有些人可能两条都声明在了html头那里了,但是其实这两种写法选其中一种就行了,因为这两条语句表达的是一样的,只是第一条比第二条要简单一点。而且utf-8跟UTF-8也是一样的,二选一就好了,下面是W3C原话:

It doesn’t matter which you use, but it’s easier to type the first one. It also doesn’t matter whether you type UTF-8 or utf-8.

在进行了编码声明过后文件也应该以相应的编码保存在磁盘。

W3C是推荐大家都采用utf-8编码网页,W3C自家网站也是用utf-8编码的。

ISO-8859-1编码(乱码)

注意:如果meta声明成<meta charset="ISO-8859-1">的,在处理中文表单时会出问题(服务器端乱码)

因为ISO-8859-1编码并不能够去编码中文的字符,所以如果在声明为ISO-8859-1编码的文档里提交中文表单的话会先把中文的字符转换成utf-8的字符串,然后再把utf-8的字符串编码进URL然后发送请求到服务器,所以最终在服务器端URL解码后得到的其实是经utf-8编码后的字符串。

下面举个例子:如果我在表单输入“你好”两个中文,因为这时候声明的ISO-8859-1编码无法编码中文,所以会把中文编码成utf-8字符串,那中文的utf-8表示是&#x4F60;&#x597D;,这时候就没有特殊字符了,字符串里面都是ISO-8859-1可以编码的,所以直接就可以把&#x4F60;&#x597D;只是把#,&这些特殊字符换成%23,%26编码进URL,编码后的URL是%26%2320320%3B%26%2322909%3B,所以当在服务器端解码的时候,得到的其实只是&#x4F60;&#x597D;这个字符串,并不是中文“你好”这两个字。

所以处理中文请不要声明为ISO-8859-1编码,用utf-8就好了。

编码优先级

HTTP响应头优先级

好了,这里就来解决上面提出的问题,有些时候可能我们会发现在html文档的head里声明<meta>标签没什么用,为什么会这样。

这里涉及到一个优先级问题,在W3C的文档里面明确表示如果浏览器收到HTTP响应头的情况下,而且在HTTP相应头中声明了文档的编码的话,那么HTTP响应头的编码的优先级会比在文档中声明的编码的优先级高

W3C原话:

If you have access to the server settings, you should also consider whether it makes sense to use the HTTP header. Note however that, since the HTTP header has a higher precedence than the in-document meta declarations, content authors should always take into account whether the character encoding is already declared in the HTTP header. If it is, the meta element must be set to declare the same encoding.

可以在浏览器开发者模式中查看浏览器收到的网页的HTTP响应头

所以这就意味着如果服务器设置了响应头Content-Type:text/html; charset=ISO-8859-1那么就算在head中声明了<meta charset="utf-8">根据HTTP头的优先级要比HTML文档中声明的优先级高,那么这时候页面就按照ISO-8859-1编码,中文就会乱码了。而且设置HTML中的<meta>解决不了问题,问题在HTTP响应头优先级更高。

BOM优先级

BOM留到最后讲,因为可能有点复杂,注意这里的BOM不是JS里面的BOM模型,这里说的BOM是byte-order mark

BOM中文名称“字节顺序标记”,是一种文档标记,标记在文档头部。

因为utf-16或utf-32,…,等的编码是等长的,就是说是操作2个字节或4个字节,所以在计算机里面就涉及到了一个多字节如何储存在内存中的概念。就好像在一些编程语言中的整形int=1;,那么在英特尔系列的处理器中是按小段法储存的,即01 00 00 00(16进制),低位字节在前高位字节在后的即为小段法。一些处理器采用大端发,如果00 00 00 01即是大端法,高位在前低位在后。读者也可以自己验证,在C语言中强制将整形指针转化为char指针,打印单个字节,可以看到在英特尔CPU的机器中低位字节是放在前面的,高位字节是放在后面的,即采用小端法。

好了,那么对于多自己的字符处理仍然有关于字节序的概念,这就是BOM标记的由来。

编码表示(十六进制)
utf-8EF BB BF
utf-16(大端)FE FF
utf-16(小端)FF FE
utf-32(大端)00 00 FE FF
utf-32(小端)FF FE 00 00

所以当检测到文件头部的标志,计算机就能够知道要用大端还是小端来解析这些字节了。

而且注意:根据W3C文档,BOM标记具有最高的编码优先级
下面是W3C原话:

If you have a UTF-8 byte-order mark (BOM) at the start of your file then recent browser versions other than Internet Explorer 10 or 11 will use that to determine that the encoding of your page is UTF-8. It has a higher precedence than any other declaration, including the HTTP header.
(注意:IE10和11无效)

也就是说假如文档有BOM标记,那么浏览器会检测出文档头部的BOM标记,将用BOM标记的编码格式来编码文档,BOM标记的优先级要高于HTTP响应头和文档内部<meta>标记

所以有些文件如果有BOM标记,那么不管是改HTTP响应头或者改文档内部声明都是无效的,因为文档BOM标记优先级最高。

说个题外话

关于utf-8编码的文件有一些是有BOM标记,有一些则没有BOM标记。微软的软件大多在保存utf-8编码文件的时候都在文件头添加了三个字节的BOM标记。小编也亲测了,分别用windows的记事本和eclipse创建两个utf-8编码的html文档,然后读取文件的头三个字节,毫无疑问,windows的记事本的确在文件的头部添加了三个字节的标记,而eclipse创建的文档则没有添加头部标记。

其实从上面的表格可以看出来utf-8编码的BOM只有一种形式,大可以省略。并且因为utf-8其实是一种变长的编码,从1字节到4字节。所以操作的字节单位是单字节,并没有字节序的概念,所以也就没必要添加头部标记。

而且一些添加了BOM头部的文档并不是在所有地方都兼容,例如在php中并不会忽略前面的头部字节,所以最终文档在浏览器中的表现会很奇怪。


总结

表单的处理跟文档编码一致。

而文档的编码有优先级关系:文档BOM标记 > HTTP响应头设置 > 文档内部声明(<meta>元素


喜欢我们的内容,关注我们的公众号吧
这里写图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值