if
来选择多个源站在这一节里,我们将介绍一个比前面更复杂一点的用例。需求描述:一个加速域名需要从两个不同的源站来加载内容,具体用哪一个由请求里的x-origin
头部来决定。对于源站2,当请求对象是图片,HTML或者CSS文件时,需要在URI之前加上"/images"用来回源。需要在回源请求里携带一个x-msg2origin
头部,其值根据不同的源站有所不同。根据这个需求,我们可以写出如下的边缘逻辑:
location / {
origin_pass origin1; # 默认回源站1
origin_set_header x-msg2origin "message for origin 1";
if ($http_x_origin = "origin2") { # 检查请求头x-origin
origin_pass origin2; # 回源站2
origin_set_header x-msg2origin "message for origin 2";
rewrite /.*\.(html?|css|png|js|jpe?g) /image$uri break;
}
}
这个例子里我们用到了rewrite模块里的if
指令来检查请求头x-origin
的值,定义不同的行为。但是,由于rewrite模块和其他模块在执行时序上的差异,我们在使用if
指令的时候需要格外的小心。如果您需要在边缘逻辑里使用该指令,请务必遵循以下原则:
rewrite
指令最后需要加上break
参数。if
, set
, rewrite
, return
, break
, eval_func
)会按照他们在location配置块里出现的顺序被执行。这些指令也被称为强制型
(imperative)指令。它们的执行时间发生在请求处理的早期阶段,早于几乎所有其他的声明型
(declarative)指令。在控制台的边缘逻辑编辑器里,为了让用户能方便地区分两类指令,强制型指令呈蓝色而声明型指令为红色。不同的声明型指令在请求处理的不同阶段按需要被执行。如果有声明型指令被包含在多个if
配置块里,只有最后一个满足条件的配置块里的指令会生效。一个例子如下:location / {
if ($http_header_a != '') {
add_header has-header-a 1;
}
if ($http_header_b != '') {
add_header has-header-b 1;
}
...
}
如果header-a
和header-b
同时出现在请求头部里,只有has-header-b
会被添加到响应头里。对于 Nginx 来说这是符合预期的行为,不是一个bug。只不过,这个行为与大多数编程语言不一样而已。如果您希望了解更多技术细节,请参阅 此页面。
if
配置块里。每条指令可用的位置都描述在了文档的“可用位置”里。对于那些不能在if
配置块里使用的指令,如果他们支持变量参数,我们仍然可以通过在if
配置块用set
指令设置变量来控制他们的行为。比如这些指令: proxy_cache_valid
, proxy_redirect
以及 proxy_cookie_domain
.if
配置块里使用声明型指令。这将大大提高配置的可读性,特别是对于 Nginx 的新用户来说。前面的例子如果用如下方式来重写,其结果可能更符合用户的期望:location / {
# 根据客户端请求来定义变量的取值
if ($http_header_a != '') {
set $has_header_a 1;
}
if ($http_header_b != '') {
set $has_header_b 1;
}
# 将变量应用到声明型指令
add_header has-header-a $has_header_a;
add_header has-header-b $has_header_b;
...
}
if()
参数来实现。下面这三个修改头部的指令都支持这个参数: add_header
, origin_set_header
以及 origin_header_modify
。如果条件里需要包含源站的响应内容,这实际上是唯一的实现方法。下面是如何使用这个参数来实现前面的例子:location / {
add_header has-header-a 1 if($http_header_a != '');
add_header has-header-b 1 if($http_header_b != '');
...
}