内容协商
什么是内容协商?
内容协商是一种根据客户端可以处理的内容类型和服务器可以处理的内容类型来确定返回给客户端的内容类型的方法。这可以用来确定客户端是想要返回 HTML 还是 JSON,图像是否应该以 JPEG 或 PNG 的形式返回,支持哪种类型的压缩等等。这是通过分析四个不同的标题来完成的,每个标题都可以支持多个值选项,每个选项都有自己的优先级。
尝试手动匹配这些内容可能会非常具有挑战性。CodeIgniter 提供了 Negotiator
类,可以为您处理这些内容。
从本质上讲,内容协商只是 HTTP 规范的一部分,它允许单个资源提供多种类型的内容,从而允许客户端请求最适合他们的数据类型。
一个经典的例子是,一个无法显示 PNG 文件的浏览器只能请求 GIF 或 JPEG 图片。当服务器收到请求时,它会查看客户端请求的可用文件类型,并从其支持的图像格式中选择最佳匹配,在这种情况下,可能会选择返回 JPEG 图片。
这种协商可以发生在四种类型的数据上。
媒体/文档类型 - 这可能是图像格式,或者 HTML 与 XML 或 JSON。
字符集 - 返回的文档应设置的字符集。通常是 UTF-8。
文档编码 - 通常是结果使用的压缩类型。
文档语言 - 对于支持多种语言的网站,这有助于确定要返回哪种语言。
加载类
您可以通过 Service 类手动加载类的实例。
<?php
$negotiate = \Config\Services::negotiator();
这将获取当前请求实例并自动将其注入到 Negotiator 类中。
此类不需要单独加载。相反,可以通过此请求的 IncomingRequest
实例访问它。虽然您无法通过这种方式直接访问它,但您可以轻松地通过 negotiate()
方法访问所有方法。
<?php
$request->negotiate('media', ['foo', 'bar']);
以这种方式访问时,第一个参数是您要查找匹配项的内容类型,第二个参数是支持值的数组。
协商
在本节中,我们将讨论可以协商的四种类型的内容,并展示如何使用上面描述的两种方法来访问协商器。
媒体
首先要考虑的是处理“媒体”协商。这些由 Accept
标头提供,是所有标头中最复杂的一个。一个常见的例子是客户端告诉服务器它希望以什么格式接收数据。这在 API 中尤其常见。例如,客户端可能请求从 API 端点获取 JSON 格式的数据。
GET /foo HTTP/1.1
Accept: application/json
现在,服务器需要提供一个它可以提供的内容类型的列表。在这个例子中,API 可能能够以原始 HTML、JSON 或 XML 的形式返回数据。此列表应按优先级排序提供。
<?php
$supported = [
'application/json',
'text/html',
'application/xml',
];
$format = $request->negotiate('media', $supported);
// or
$format = $negotiate->media($supported);
在这种情况下,客户端和服务器都可以同意将数据格式化为 JSON,因此从协商方法返回“json”。默认情况下,如果找不到匹配项,将返回 $supported
数组中的第一个元素。但是,在某些情况下,您可能需要强制格式严格匹配。如果您将 true
作为最终值传递,则如果找不到匹配项,它将返回一个空字符串。
<?php
$format = $request->negotiate('media', $supported, true);
// or
$format = $negotiate->media($supported, true);
语言
另一个常见用法是确定应以何种语言提供内容。如果您只运行单语言网站,这显然不会有太大区别,但任何可以提供多种语言翻译内容的网站都会发现这很有用,因为浏览器通常会在 Accept-Language
标头中发送首选语言。
GET /foo HTTP/1.1
Accept-Language: fr; q=1.0, en; q=0.5
在这个例子中,浏览器更喜欢法语,其次是英语。如果您的网站支持英语和德语,您将执行以下操作:
<?php
$supported = [
'en',
'de',
];
$lang = $request->negotiate('language', $supported);
// or
$lang = $negotiate->language($supported);
在这个例子中,将返回“en”作为当前语言。如果找不到匹配项,它将返回 $supported
数组中的第一个元素,因此它应该始终是首选语言。
编码
Accept-Encoding
标头包含客户端首选接收的字符集,用于指定客户端支持的压缩类型。
GET /foo HTTP/1.1
Accept-Encoding: compress, gzip
您的 Web 服务器将定义您可以使用的压缩类型。有些,比如 Apache,只支持 **gzip**。
<?php
$type = $request->negotiate('encoding', ['gzip']);
// or
$type = $negotiate->encoding(['gzip']);
在 维基百科 上了解更多信息。
字符集
所需的字符集通过 Accept-Charset
标头传递。
GET /foo HTTP/1.1
Accept-Charset: utf-16, utf-8
默认情况下,如果找不到匹配项,将返回 **utf-8**。
<?php
$charset = $request->negotiate('charset', ['utf-8']);
// or
$charset = $negotiate->charset(['utf-8']);