请求转发(forward)是由服务器直接访问目标地址的 URL,然后读取响应的内容并把这些内容发给浏览器。
由于这个跳转过程在服务器内部实现,因此浏览器并不知道服务器发送的内容来自何处,所以它的地址栏还是原来的地址。
重定向(redirect,即重写,rewrite)是服务端根据逻辑,返回一个状态码给浏览器,告诉它重新请求的地址,因此地址栏显示的是新的 URL。
临时重定向(302 状态码),搜索引擎认为新的网址只是暂时的,所以它会在抓取新内容的同时保留旧的网址。
永久重定向(301 状态码),搜索引擎在抓取新内容的同时也会将旧的网址替换为重定向之后的网址。
转发和重定向的区别如下:
浏览器地址栏
请求转发时,地址栏中的地址不变;请求重定向时,地址栏中的地址变为新的 URL。
数据共享
请求转发时,转发页面和转发到的页面可以共享 request 里的数据;请求重定向时不能共享数据。
应用范围
请求转发一般用于用户登录时,根据角色转发到相应的地方。
请求重定向一般用于用户注销返回主页面以及跳转到其他网站时。
效率
转发的效率高于重定向的效率。
重写指令
nginx 的 ngx_http_rewrite_module 模块用于通过 PCRE 正则表达式来重写请求 URI。此模块中的 break、if、return、rewrite 以及 set 指令(重写指令)按下述顺序处理:
当这些重写指令位于 server 上下文中时,它们将在被请求的 location 确定之前按序执行。
根据请求 URI 查找有关 location
若 location 中也包含这些重写指令时,它们按序执行。
若在 location 中执行重写指令产生了新的 URI,那么会根据新 URI 确定新的 location。这样的循环可以最多执行 10 次,超过后 Nginx 将返回 500 错误。
break 指令(server、location 和 if 上下文)用于完成当前设置的规则并停止执行其他的重写指令。
if ($slow) {
limit_rate 10k;
break;
}
若 $slow 为真,则设置 limit_rate,然后执行 break 指令。
if 指令(server 和 location 上下文)用于判断一个条件,若条件成立,则执行其包含的语句。
if ($http_user_agent ~ MSIE) {
rewrite ^(.*)$ /msie/$1 break;
}
若 User-Agent 匹配 MSIE,则执行 rewrite 指令重写 URL。
if 指令可判断的条件包括:
变量名,若变量值为空字符串或 0 则为 false。
使用 = 和 != 操作符来比较字符串。
使用 ~* 和 ~ 匹配的正则表达式。
* 表示大小写不敏感。
使用 -f 和 !-f 来检查文件是否存在。
使用 -d 和 !-d 来检查目录是否存在。
使用 -e 和 !-e 来检查文件、目录或软链接是否存在。
使用 -x 和 !-x 来检查是否为可执行文件。
return 指令(server、location 和 if 上下文)结束执行配置语句并为客户端返回状态代码。
返回非标准的 444 状态码会在不发送任何响应首部的情况下关闭连接。
rewrite 指令(server、location 和 if 上下文)按照相关的正则表达式与字符串修改 URI,此指令会按在配置文件中出现的顺序执行。
server {
...
rewrite ^(/download/.*)/media/(.*)\..*$ $1/mp3/$2.mp3 last;
return 403;
...
}
若请求 URL 以 /download/ 开头,且包含 /media/,则重写为包含 /mp3/ 且以 mp3 结尾的 URL。
若这些指令放置在 location /download/ { ... } 上下文中,last 标志应替换为 break 标志,否则 Nginx 会执行 10 次循环并返回 500 错误。
若替换字符串包含新的请求参数,那么先前的请求参数会附加在其后。若这不是期望的,那么在替换字符串尾部放置 ? 字符避免附加。
若正则表达式包含 } 或 ; 字符,那么整个表达式应包含在 ‘‘ 或 "" 中。
若替换字符串以 http://、https:// 或 $scheme 开头,请求将被重定向,并且不会再执行其余的 rewrite 指令。
rewrite 指令尾部可添加标记(flag),标记可为以下值:
last,完成 rewrite 指令后搜索匹配新 URI 的 location。
break,完成 rewrite 指令后停止执行其他的重写指令。
redirect,返回 302 临时重定向。若替换字符串不是以 http://、https:// 或 $scheme 开头时使用。
permanent,返回 301 永久重定向。
若一个重定向使用的是相对路径(没有主机名部分),那么 Nginx 在重定向的过程中将使用匹配 server_name 指令的 Host 头或 server_name 指令指定的第一个名称作为其主机名。
若 Host 头不匹配或不存在且没有设置 server_name,将会使用本地主机名。若总是想让 Nginx 使用 Host 头,那可在 server_name 中使用 * 通配符。
rewrite_log 指令(http、server、location 和 if 上下文)启用时将在 error log 中记录 notice 标记的重写日志。
值为 on 或 off。
set 指令(server、location 和 if 上下文)用于设置一个变量并为其赋值,值可以是文本、变量或它们的组合。
不能使用 set 指令设置 $http_xxx 头部变量的值。
uninitialized_variable_warn 指令(http、server、location 和 if 上下文)用于开启或关闭在未初始化变量中记录警告日志。
值为 on 或 off。
配置 URL 重写
Nginx 中 URL 重写的配置如下:
location ^~ / {
root html;
index index.html index.htm;
rewrite ^/bbs/(.*)$ http://192.168.0.202/forum/$1;
}
将以 /bbs/ 开头的请求重定向到 http://192.168.0.202/forum/$1。
内部实现
ngx_http_rewrite_module 模块的重写指令在配置阶段被编译成在请求处理期间被解释的内部指令,解释器是一个简单的虚拟堆栈器。例如,下述指令:
location /download/ {
if ($forbidden) {
return 403;
}
if ($slow) {
limit_rate 10k;
}
rewrite ^/(download/.*)/media/(.*)\..*$ /$1/mp3/$2.mp3 break;
}
会被解释成下述指令:
variable $forbidden
check against zero
return 403
end of code
variable $slow
check against zero
match of regular expression
copy "/"
copy $1
copy "/mp3/"
copy $2
copy ".mp3"
end of regular expression
end of code
由于 limit_rate 指令与 ngx_http_rewrite_module 模块无关,所以此处没有它对应的指令。
此处为 if 块创建了一个单独的配置,若条件为真,则执行它包含的指令。
若将 rewrite 指令的第一个 "/" 字符放入 "()" 内,即:
rewrite ^(/download/.*)/media/(.*)\..*$ /$1/mp3/$2.mp3 break;
那它被解释成的指令将按如下所示,这减少了一条 copy 语句。
match of regular expression copy $1 copy "/mp3/" copy $2 copy ".mp3" end of regular expression end of code