编码只是需要正确完成的事情之一。 如果做错了,一切似乎都坏了,什么也没有做。 如果做对了,没有人会注意到。 这使得处理编码非常烦人。
尽管如此,我们还是很幸运的,并且大多数事情已经做好了充分的准备。 我们只需要确保使用正确的编码保存(和传输)我们的文档即可。 正确的编码是我们指定的编码。 只要包含我们需要的所有字符,并且只要我们保持一致,就可以。
HTML有三个重要的文本编码规则:
- 使用正确的编码加载内容。
- 以相同的编码传输内容。
- 确保客户端读取具有指定编码的内容。
在本文中,我们将更详细地仔细研究这三个规则,尤其是第二和第三条规则。 最后,我们还将研究表单编码,它与文本编码直接无关,但与文本编码间接无关。 我们将看到为什么存在某种联系。
选择正确的编码
我们要么直接知道我们的内容应该以某种特殊的编码方式传递,要么我们应该选择UTF-8。 我们要使用UTF-8的原因有很多。 这不是将字符存储在内存中的好格式,但它作为数据交换和内容传输的基础很好。 从本质上讲,这是显而易见的。 但是,更常见的错误之一是在没有正确编码的情况下保存文件。 因为没有编码的文本,我们应该仔细选择编码。
Sublime Text和大多数其他文本编辑器的用户可能从未遇到过编码错误的问题,因为这些编辑器默认情况下以UTF-8保存。 有一些编辑器(主要是Windows平台)使用不同的默认格式,例如Windows-1252。
即使在Sublime Text中,更改文件的编码也是更标准的操作之一。 在“ 文件”菜单中,选择“ 使用编码保存”,然后选择所需的文件 。 而已!
原则上,每个更高级的编辑器都应具有此类选项。 有时它们包含在高级保存菜单中。 例如,Microsoft Visual Studio的编辑器在“ 文件”菜单中单击“ 高级保存选项”后会触发一个特殊对话框。
我们应该确保使用正确的编码。 这将使用相应的字节作为内容。 UTF-8的主要优点是,如果我们不使用特殊字符,则只需要一个字节。 每个字符最多消耗4个字节。 这是动态的,使UTF-8成为文本存储和传输的理想格式。 需要注意的是,UTF-8不是使用内存中字符串的最佳格式。
控制变速箱
HTTP协议以纯文本形式传输数据。 即使我们决定将传输的内容编码为GZip或使用对内容进行加密的HTTPS,底层内容仍然只是纯文本。 我们已经了解到,不存在纯文本这样的东西。 我们总是需要将内容与某种编码相关联以获得文本表示。
HTTP消息分为两部分。 上部称为标题。 下半部用空心线分隔:主体。
总有至少两个HTTP消息:一个请求及其相关的响应。 两种消息都共享此结构。 响应的主体是我们要传输的内容。 请求的正文仅与表单提交有关,稍后我们将予以关注。 如果要提供有关内容编码的某些信息,则必须在标头中提供一些信息。
下面的标头使用UTF-8字符集告诉接收方正文包含称为HTML的特殊文本格式。
Content-Type: text/html; charset=utf-8
还有Content-Encoding
标头。 我们可以轻松地将内容编码与内容的实际文本编码混淆。 前者用于指定整个程序包的编码,例如GZip,而后者则用作初始设置,例如,解析提供的内容。
如果我们关心此步骤的正确性,则必须确保我们的Web服务器发送正确的标头。 大多数Web框架都提供了这种功能。 在PHP中,我们可以编写:
header('Content-Type:text/html; charset=utf-8');
在Node.js中,我们可能要使用以下内容,其中res
是代表请求的变量:
res.setHeader('Content-Type', 'text/html; charset=utf-8');
传输的标题会将HTML输入的文本扫描器设置为提供的设置。 在前面的示例中,我们使用UTF-8 。 但是请稍等:初始设置! 有许多方法可以覆盖此问题。 如果实际内容不是UTF-8,则扫描仪可能会识别出此内容并更改设置。 可以通过字节顺序标记(称为BOM)检测或通过在内容中找到特定于编码的模式来触发此类更改。 相比之下,前者则寻找人为添加的模式。
最后,由于我们HTML代码,编码可能会更改。 只能更改一次。
固定编码
DOM构造函数击中meta
标签后,它将查找charset
声明。 如果找到一个,则将提取字符集。 如果我们可以成功提取它并且编码有效,则可以设置新的编码以扫描其他字符。 此时,编码将被冻结,并且无法进行进一步的更改。
只有一个警告。 要检查以前的扫描是否还可以,我们需要将已经扫描的字符与将要扫描的字符进行比较。 因此,我们需要查看更早更改编码是否会有所不同。 如果发现差异,则需要重新启动整个解析过程。 否则,到目前为止,整个DOM结构可能都是错误的。
结果,我们已经吸取了两个教训:
- 尽快放置
<meta charset=utf-8>
(或其他编码)标签。 - 在HTML中指定
charset
属性之前,只能使用ASCII字符。
最后,一个好的样板启动器如下所示。 正如我们在上一篇文章中了解到的,我们可以省略head
和body
标签。 该代码片段正确执行了两件事:使用正确的文档类型,并尽快选择字符集。
<!DOCTYPE html>
<html lang="en">
<meta charset="utf-8">
<title>Title here</title>
<!-- ... -->
剩下的唯一问题是:如果我忘记了这三个步骤之一,会发生什么? 好吧,第一步和第三步是最重要的。 传输实际上还不错。 如果未从HTTP标头给出初始编码,则浏览器将根据用户的语言环境选择初始编码。 在德语语言环境中,我们获得Windows-1252。 实际上,这是大多数国家/地区的默认设置。 一些国家(例如波兰或匈牙利)选择Latin2 ,也称为iso-8859-2 。
原则上,如果我们遵循前面描述的最佳实践,则不必担心这种初始编码。 ASCII是Unicode的子集,实际上列出的大多数编码只是ASCII扩展,可以满足一个或多个国家/地区的特定需求。 如果在指定字符集之前仅使用基本ASCII字符,那应该没问题。
更严重的是存储/读取或生成的数据(传递给客户端)与meta
标记中的语句之间的冲突。 如果出现问题,我们可能会看到如下所示的效果图。 这不是令人愉快的用户体验。
回到确定正确的编码,有很多原因使UTF-8成为最佳选择。 对于我们要显示的字符,任何其他编码至少应足够。 但是,如果我们提供表单输入字段,则可能会遇到麻烦。 在这一点上,我们不再控制已使用的字符。 允许用户在此处输入任何内容。 让我们看看如何控制表单输入的编码。
提交表格
使用某种编码类型提交表单,该编码类型与服务器响应的编码类型(例如GZip)不同。 表单的编码类型确定表单在发送到服务器之前如何序列化。 与HTTP动词结合使用时特别有用。
普通表单提交使用POST
作为HTTP动词,但是GET
, PUT
和DELETE
也是常见的。 应该仅POST
和PUT
将主体用于请求中的内容传输。 浏览器将根据<form>
元素的enctype
属性的选择来构造内容,并指定编码类型。 通过在HTTP请求中设置Content-Type
标头来传输编码类型。
有三种公认的编码类型:
- URL编码(默认值,显式application / x-www-form-urlencoded )
- 纯文本( 纯文本/纯文本 )
- 分段 ( multipart / form-data )
第一个和第二个非常相似,但是它们之间存在细微(非常重要)的差异。 第三种变体是最强大的方法。 它甚至允许将任意文件作为附件进行传输。
前两种类型之间的主要区别在于URL编码以传输百分比的形式对所有名称和值进行编码,而这不是通过纯文本完成的。 百分比编码确保接收方可以区分名称和值。 纯文本表单提交不存在此保证。 第三个变体使用边界字符串来分隔条目,这在构造上是唯一的。
让我们通过提交一个简单的表格来可视化差异。 该表格包含以下代码:
在不指定任何编码类型的情况下提交表单将传递以下内容:
first=With+spaces%2Bsigns&second=H%E4llo+D%FC%3F&third=Multi%0D%0Alines%0D%0Arock
URL编码将空格字符转换为加号。 像所有“特殊”字符一样,现有的加号由百分比编码规则转换。 这尤其适用于最初由\r\n
表示的新行,现在显示为%0D%0A
。
让我们看看纯文本编码的结果如何。
first=With spaces+signs
second=Hällo Dü?
third=Multi
lines
rock
两行之间用新行分隔。 这对于多行内容尤其成问题,并且可能导致不正确的表示。
多部分编码以一种方式将纯文本提交的优点与已定义的边界相结合,从根本上解决了纯文本编码的问题。 唯一的缺点是内容长度增加。
------WebKitFormBoundaryzQRASBvDO1bUB5Lp
Content-Disposition: form-data; name="first"
With spaces+signs
------WebKitFormBoundaryzQRASBvDO1bUB5Lp
Content-Disposition: form-data; name="second"
Hällo Dü?
------WebKitFormBoundaryzQRASBvDO1bUB5Lp
Content-Disposition: form-data; name="third"
Multi
lines
rock
------WebKitFormBoundaryzQRASBvDO1bUB5Lp--
最后两种形式的编码方法还显示了与我们输入的完全相同的特殊字符。 表单传输主要使用相应<form>
元素的accept-charset
属性。 如果未提供此类属性,则使用页面的编码。 同样,设置正确的编码很重要。
将来,我们将看到第四种编码类型,称为application/json
。 顾名思义,它将表单内容打包到JSON字符串中。
结论
选择正确的编码就像选择UTF-8一样容易。 通过始终使用相同的编码可以避免典型的问题。 尽管不是必需的,但在传输过程中声明编码肯定很有用,尽管不是必须的,特别是如果我们遵循最佳实践,将<meta>
元素与charset
属性一起放置的话。
表单提交是一个依赖正确编码选择的过程-不仅对于文本,而且对于提交本身。 通常,即使在大多数情况下默认编码类型可能更好(更小),我们也始终可以选择multipart/form-data
作为enctype
。 在生产中,我们永远不要使用text/plain
。
翻译自: https://code.tutsplus.com/tutorials/html5-mastery-encoding--cms-24841