Apache HTTPD支持HTTP / 1.1规范中所述的内容协商。它可以根据浏览器提供的媒体类型,语言,字符集和编码的首选项来选择资源的最佳表示形式。它还实现了一些功能,可以更智能地处理来自发送不完整协商信息的浏览器的请求。
内容协商由mod_negotiation
模块提供
,默认情况下已编译。
资源可能有几种不同的表示形式。例如,它可能以不同的语言或不同的媒体类型或它们的组合提供。选择最合适的选择的一种方法是为用户提供索引页,然后让他们选择。但是,服务器通常可以自动选择。之所以可行,是因为浏览器可以在每个请求中发送有关他们喜欢哪种表示形式的信息。例如,浏览器可能指示希望以法语查看信息,如果可能,则以英语显示。浏览器通过请求中的标头指示其首选项。要仅请求法语表示,浏览器将发送
Accept-Language: fr
请注意,只有在可以选择表示形式并且它们随语言而变化时,才会应用此首选项。
作为更复杂的请求的示例,此浏览器已配置为接受法语和英语,但更喜欢法语,并接受各种媒体类型,比纯文本或其他文本类型更喜欢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服务器提供对名称空间内资源表示的访问,每种表示形式都是具有定义的媒体类型,字符集,编码等的字节序列形式。每个资源都可以关联在任何给定时间具有零个,一个或多个表示。如果有多个表示形式,则该资源被称为可协商资源,并且其每个表示形式都称为Variant。其中用于流通资源的变异而变化的方式被称为维谈判。
为了协商资源,需要为服务器提供有关每个变体的信息。这可以通过以下两种方式之一来完成:
*.var
文件),其中包含姓名的明确变种文件,或类型映射是一个文档,该文档与名为的处理程序相关联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的内容协商功能,不必知道实际上如何进行协商的任何细节。但是,本文的其余部分将为感兴趣的人介绍所使用的方法。
有两种协商方法:
尺寸 | 笔记 |
---|---|
媒体类型 | 浏览器使用Accept
标题字段指示首选项。每个项目都可以具有关联的品质因数。变体描述也可以具有品质因数(“ qs”参数)。 |
语言 | 浏览器使用Accept-Language 标题字段指示首选项
。每个项目都可以有一个品质因数。变体可以与一种,一种或多种语言关联。 |
编码方式 | 浏览器用Accept-Encoding 标题字段指示首选项
。每个项目都可以有一个品质因数。 |
字符集 | 浏览器用Accept-Charset 标题字段指示首选项
。每个项目都可以有一个品质因数。变体可以将字符集指示为媒体类型的参数。 |
httpd可以使用以下算法来选择“最佳”变体(如果有)以返回到浏览器。该算法无法进一步配置。其操作如下:
Accept
标头中的质量因子与该变体媒体类型的源质量因子相乘,然后选择具有最高值的变体。Accept-Language
标题中的语言顺序(如果存在)或LanguagePriority
伪指令中的语言顺序(如果存在),选择具有最佳语言匹配的变体
。Accept-Charset
标题行所示,选择具有最佳字符集媒体参数的变体。除非明确排除,否则Charset ISO-8859-1是可以接受的。具有text/*
媒体类型但未明确与特定字符集关联的变体假定为在ISO-8859-1中。Vary
设置为指示协商的范围(浏览器和缓存可在缓存资源时使用此信息)。结束。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,以模拟所需的行为。还将“类型/ *”格式的通配符的q值设置为0.02(因此,与“ * / *”匹配时,通配符的q值更可取。如果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.html.en | foo foo.html |
-- |
foo.en.html | 富 | foo.html |
foo.html.en.gz | foo foo.html |
foo.gz foo.html.gz |
foo.en.html.gz | 富 | 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
环境变量。