内容协商
请注意,只有在可以选择表示形式并且它们随语言而变化时,才会应用此首选项。
作为更复杂的请求的示例,此浏览器已配置为接受法语和英语,但更喜欢法语,并接受各种媒体类型,比纯文本或其他文本类型更喜欢HTML,比其他媒体类型更喜欢GIF或JPEG ,但也允许任何其他媒体类型作为不得已的选择:
Accept-Language: fr; q=1.0, en; q=0.5 Accept: text/html; q=1.0, text/*; q=0.8, image/gif; q=0.6, image/jpeg; q=0.6, image/*; q=0.5, */*; q=0.1
httpd支持HTTP / 1.1规范中定义的“服务器驱动”内容协商。它完全支持Accept
,Accept-Language
,Accept-Charset
和Accept-Encoding
请求头。httpd还支持“透明”内容协商,这是RFC 2295和RFC 2296中定义的实验性协商协议。它不提供对这些RFC中定义的“功能协商”的支持。
甲资源是由URI(RFC 2396)识别的概念实体。像Apache HTTP Server这样的HTTP服务器提供对名称空间内资源表示的访问,每种表示形式都是具有定义的媒体类型,字符集,编码等的字节序列形式。每个资源都可以关联在任何给定时间具有零个,一个或多个表示。如果有多种表示形式,则该资源称为可转让资源,并且每种表示形式都称为“变体”。其中用于流通资源的变异而变化的方式被称为维谈判。
在httpd中进行协商
为了协商资源,需要为服务器提供有关每个变体的信息。这可以通过以下两种方式之一完成:
- 使用类型映射(即,一个
*.var
文件),其中包含姓名的明确变种文件,或 - 使用“ MultiViews”搜索,服务器进行隐式文件名模式匹配,然后从结果中进行选择。
使用类型图文件
类型映射是与名为的处理程序相关联的文档type-map
(或者,对于与较早的httpd配置具有向后兼容性,则为MIME-type application/x-type-map
)。请注意,要使用此功能,必须在配置中设置一个处理程序,该处理程序将文件后缀定义为type-map
;。最好用
AddHandler type-map .var
在服务器配置文件中。
类型映射文件应与它们描述的资源具有相同的名称,后跟扩展名.var
。在下面显示的示例中,资源被命名为foo
,因此类型映射文件被命名为foo.var
。
该文件应为每个可用变体都有一个条目。这些条目由连续的HTTP格式的标题行组成。不同变体的条目由空白行分隔。空行在条目中是非法的。通常,以一个用于整个合并实体的条目开始一个映射文件(尽管这不是必需的,并且如果存在则将被忽略)。下面显示了一个示例地图文件。
该文件中的URI相对于类型映射文件的位置。通常,这些文件与类型映射文件位于同一目录中,但这不是必需的。您可以为与映射文件位于同一服务器上的任何文件提供绝对或相对URI。
URI: foo URI: foo.en.html Content-type: text/html Content-language: en URI: foo.fr.de.html Content-type: text/html;charset=iso-8859-2 Content-language: fr, de
还要注意,即使打开“多视图”,类型映射文件也将优先于文件名的扩展名。如果变体具有不同的源质量,则可以通过媒体类型的“ qs”参数来表示,如下图所示(以JPEG,GIF或ASCII艺术形式提供):
URI: foo URI: foo.jpeg Content-type: image/jpeg; qs=0.8 URI: foo.gif Content-type: image/gif; qs=0.5 URI: foo.txt Content-type: text/plain; qs=0.01
qs值可以在0.000到1.000的范围内变化。请注意,将永远不会选择qs值为0.000的任何变体。没有“ qs”参数值的变体的qs系数为1.0。qs参数指示此变量与其他可用变量相比的相对“质量”,而与客户端的功能无关。例如,如果JPEG文件试图表示照片,则其源质量通常比ASCII文件高。但是,如果要表示的资源是原始ASCII艺术,则ASCII表示的源质量将比JPEG表示的源质量高。因此,qs值特定于给定的变量,具体取决于它代表的资源的性质。
可以在mod_negotiation typemap文档中找到已识别的标头的完整列表。
多视图
MultiViews
是每个目录的选项,这意味着可以使用,或部分(如果正确设置)中的Options
指令在文件中进行设置。注意没有设置;您必须按名称要求。<Directory>
<Location>
<Files>
httpd.conf
AllowOverride
.htaccess
Options All
MultiViews
效果MultiViews
如下:如果服务器收到一个请求/some/dir/foo
,如果/some/dir
已经MultiViews
启用,并/some/dir/foo
不会不存在,则服务器会寻找一个名为foo的文件的目录*,并有效假货一个类型的地图,名称所有这些文件。,为其分配相同的媒体类型和内容编码(如果客户端按名称要求提供其中一种)。然后,它选择最适合客户要求的匹配项。
MultiViews
DirectoryIndex
如果服务器尝试索引目录,则也可能适用于搜索以伪指令命名的文件。如果配置文件指定
DirectoryIndex index
那么服务器将在index.html
和之间进行仲裁(index.html3
如果两者均存在)。如果两者都不index.cgi
存在,则服务器将运行它。
如果在读取目录时找到的文件之一没有可识别mod_mime
其文件集,内容类型,语言或编码的扩展名,则结果取决于MultiViewsMatch
指令的设置。该指令确定处理程序,过滤器和其他扩展类型是否可以参与MultiViews协商。
谈判方式
httpd从类型映射文件或目录中的文件名获取给定资源的变体列表之后,它会调用两种方法之一来确定要返回的“最佳”变体(如果有)。为了使用httpd的内容协商功能,不必知道实际上如何进行协商的任何细节。但是,本文的其余部分将为感兴趣的人介绍所使用的方法。
有两种协商方法:
- 在正常情况下,使用带有httpd算法的服务器驱动的协商。以下将详细说明httpd算法。使用此算法时,httpd有时可以“弄乱”特定维度的质量因数以获得更好的结果。下面将详细介绍httpd修饰质量因子的方式。
- 当浏览器通过RFC 2295中定义的机制专门请求透明内容协商时,将使用透明内容协商。这种协商方法使浏览器可以完全控制“最佳”变体的确定,因此结果取决于浏览器使用的特定算法。作为透明协商过程的一部分,浏览器可以要求httpd运行RFC 2296中定义的“远程变量选择算法”。
谈判范围
尺寸 | 笔记 |
---|---|
媒体类型 | 浏览器通过Accept 标题字段指示首选项。每个项目都可以具有关联的品质因数。变体描述也可以具有品质因数(“ qs”参数)。 |
语言 | 浏览器通过Accept-Language 标题字段指示首选项。每个项目都可以有一个品质因数。变体可以与一种,一种或多种语言关联。 |
编码方式 | 浏览器用Accept-Encoding 标题字段指示首选项。每个项目都可以有一个品质因数。 |
字符集 | 浏览器用Accept-Charset 标题字段指示首选项。每个项目都可以有一个品质因数。变体可以将字符集指示为媒体类型的参数。 |
httpd协商算法
httpd可以使用以下算法来选择“最佳”变体(如果有)以返回到浏览器。该算法无法进一步配置。其操作如下:
- 首先,对于协商的每个维度,请检查相应的Accept *标头字段,并为每个变量指定质量。如果任何尺寸的Accept *标头表示此变体不可接受,请消除它。如果没有其他型号,请转到步骤4。
- 通过淘汰过程选择“最佳”变体。依次进行以下每个测试。消除了每次测试未选择的任何变体。每次测试后,如果只剩下一个变体,请选择它作为最佳匹配,然后继续执行步骤3。如果还有一个以上的变体,请继续进行下一个测试。
- 将
Accept
标头中的质量因子与该变体媒体类型的源质量因子相乘,然后选择具有最高值的变体。 - 选择具有最高语言品质因数的变体。
- 使用
Accept-Language
标题中的语言顺序(如果存在)或指令中的语言顺序(如果存在),选择具有最佳语言匹配的变体LanguagePriority
。 - 选择具有最高“级别”媒体参数的变体(用于提供text / html媒体类型的版本)。
- 如
Accept-Charset
标题行所示,选择具有最佳字符集媒体参数的变体。除非明确排除,否则Charset ISO-8859-1是可以接受的。具有text/*
媒体类型但未明确与特定字符集关联的变体被假定为在ISO-8859-1中。 - 选择那些关联的字符集媒体参数不是 ISO-8859-1的变量。如果没有此类变量,请选择所有变量。
- 选择具有最佳编码的变体。如果存在带有用户代理可接受的编码的变体,请仅选择这些变体。否则,如果混合了编码变体和非编码变体,则仅选择未编码变体。如果所有变体均已编码或所有变体均未编码,请选择所有变体。
- 选择内容长度最小的变体。
- 选择其余的第一个变体。这将是类型映射文件中第一个列出的文件,或者是从目录中读取变体的文件,当使用ASCII码顺序排序时,其文件名将排在第一位。
- 将
- 该算法现在选择了一个“最佳”变体,因此将其作为响应返回。HTTP响应标头
Vary
设置为指示协商的范围(浏览器和缓存可在缓存资源时使用此信息)。结束。 - 到达此处意味着未选择任何变体(因为浏览器不接受任何变体)。返回406状态(表示“没有可接受的表示形式”),其响应正文由列出可用变体的HTML文档组成。还要设置HTTP
Vary
标头以指示差异的大小。
摆弄质量价值观
httpd有时会通过严格解释上面的httpd协商算法来改变质量值。对于未发送完整或准确信息的浏览器,这是从算法中获得更好的结果。一些最受欢迎的浏览器会发送Accept
标头信息,否则,在许多情况下,这些信息会导致选择错误的变体。如果浏览器发送了完整且正确的信息,则将不会应用这些小提琴。
媒体类型和通配符
的Accept:
请求报头指示介质类型的偏好。它还可以包括“通配符”媒体类型,例如"image/*"
或"*/*"
,其中*匹配任何字符串。因此,请求包括:
Accept: image/*, */*
表示以“ image /”开头的任何类型都可以接受,其他任何类型也可以。一些浏览器除了可以处理的显式类型外,还会例行发送通配符。例如:
Accept: text/html, text/plain, image/gif, image/jpeg, */*
这样做的目的是表明首选显式列出的类型,但是如果可以使用其他表示形式,也可以。使用明确的质量值,浏览器真正想要的是:
Accept: text/html, text/plain, image/gif, image/jpeg, */*; q=0.01
显式类型没有品质因数,因此它们的默认优先级为1.0(最高)。通配符*/*的优先级较低,为0.01,因此,如果没有任何变量与明确列出的类型匹配,则仅返回其他类型。
如果Accept:
标头根本不包含任何 q因子,则httpd将q *的“*/*”值(如果存在)设置为0.01,以模拟所需的行为。它还会将格式为“ type /*”的通配符的q值设置为0.02(因此,与通配符“*/*”相比,它们的优先级更高。如果Accept:
标头上的任何媒体类型包含aq因数,则不会应用这些特殊值,因此,来自浏览器的请求会发送明确的信息以按预期开始工作。
语言协商异常
httpd 2.0中的新功能,已将一些例外添加到协商算法中,以便在语言协商无法找到匹配项时允许适当的回退。
当客户端请求服务器上的页面,但服务器找不到与Accept-language
浏览器发送的页面匹配的页面时,服务器将向客户端返回“ No Acceptable Variant”或“ Multiple Choices”响应。为了避免这些错误消息,可以将httpd配置为Accept-language
在这种情况下忽略,并提供与客户端的请求不明确匹配的文档。该ForceLanguagePriority
指令可用于覆盖这些错误消息之一或全部,并以LanguagePriority
指令的形式替代服务器的判断。
如果找不到其他匹配项,服务器还将尝试匹配语言子集。例如,如果客户端请求使用en-GB
英式英语语言的文档,则HTTP / 1.1标准通常不允许服务器将其与标记为simple的文档进行匹配en
。(请注意,几乎肯定会包含配置错误,en-GB
而不是包含en
在Accept-Language
标头中,因为读者不太可能会理解英式英语,但通常不会理解英语。不幸的是,许多当前客户端的默认配置与此类似。)但是,如果没有其他语言匹配是可能的,并且服务器将返回“ No Acceptable Variants”错误或回退到LanguagePriority
,服务器将忽略该子集规范和匹配en-GB
反对en
文件。隐式地,httpd会将父语言以非常低的质量值添加到客户可接受的语言列表中。但是请注意,如果客户端请求“ en-GB; q = 0.9,fr; q = 0.8”,并且服务器具有指定为“ en”和“ fr”的文档,则将返回“ fr”文档。这对于保持符合HTTP / 1.1规范并与正确配置的客户端有效地工作是必需的。
为了支持高级技术(例如cookie或特殊的URL路径)来确定用户的首选语言,因为httpd 2.0.47可以mod_negotiation
识别环境变量prefer-language
。如果存在并且包含适当的语言标签,mod_negotiation
将尝试选择匹配的变体。如果没有此类变体,则适用正常的协商过程。
例
SetEnvIf Cookie "language=(.+)" prefer-language=$1 Header append Vary cookie
透明内容协商的扩展
httpd扩展了透明内容协商协议(RFC 2295),如下所示。{encoding ..}
在变体列表中使用一个新元素来标记变体,这些变体仅可用于特定的内容编码。扩展了RVSA / 1.0算法(RFC 2296)的实现,以识别列表中的编码变体,并在根据Accept-Encoding
请求标头接受编码时,将其用作候选变体。在选择最佳变体之前,RVSA / 1.0实现不会将计算出的质量因数四舍五入到小数点后五位。
关于超链接和命名约定的注意事项
如果使用语言协商,则可以在不同的命名约定之间进行选择,因为文件可以具有多个扩展名,并且扩展名的顺序通常是无关紧要的(有关详细信息,请参见mod_mime文档)。
一个典型的文件有一个MIME类型的扩展名(例如,html
),也许编码扩展(例如,gz
),当然还有语言扩展(例如,en
)当我们有这个文件的不同语言版本。
例子:
- foo.en.html
- foo.html.en
- foo.en.html.gz
以下是一些文件名示例以及有效和无效的超链接:
Filename | Valid hyperlink | Invalid hyperlink |
---|---|---|
foo.html.en | foo foo.html | - |
foo.en.html | foo | foo.html |
foo.html.en.gz | foo foo.html | foo.gz foo.html.gz |
foo.en.html.gz | foo | foo.html foo.html.gz foo.gz |
foo.gz.html.en | foo foo.gz foo.gz.html | foo.html |
foo.html.gz.en | foo foo.html foo.html.gz | foo.gz |
查看上表,您会发现始终可以使用名称,而无需在超链接中添加任何扩展名(例如,foo
)。好处是您可以隐藏rsp文档的实际类型。文件,以后可以更改它,例如,从更改html
为shtml
或cgi
不更改任何超链接引用。
如果你想继续在超链接(使用MIME类型如foo.html
)的语言扩展(包括如果有一个编码扩展)必须在MIME类型的扩展名(右侧例如,foo.html.en
)。
关于缓存的注意事项
缓存存储表示形式时,会将其与请求URL关联。下次请求URL时,缓存可以使用存储的表示形式。但是,如果资源在服务器上可协商,则可能导致仅第一个请求的变体被缓存,并且随后的缓存命中可能返回错误的响应。为避免这种情况,httpd通常会将内容协商后返回的所有响应标记为HTTP / 1.0客户端不可缓存。httpd还支持HTTP / 1.1协议功能,以允许缓存协商的响应。
对于来自HTTP / 1.0兼容客户端(浏览器或缓存)的请求,该指令CacheNegotiatedDocs
可用于允许缓存需要协商的响应。该指令可以在服务器配置或虚拟主机中给出,并且不带参数。它对来自HTTP / 1.1客户端的请求没有影响。
对于HTTP / 1.1客户端,httpd发送Vary
HTTP响应标头以指示响应的协商维度。缓存可以使用此信息来确定是否可以从本地副本满足后续请求。为了鼓励缓存使用本地副本而不管协商范围如何,请设置force-no-vary
环境变量。