location指令的使用
location指令要放在server模块里面,语法如下:
server{
location 修饰符 URI {
[具体配置]
}
}
location指令是干嘛用的?
根据官方文档,location的作用是:Sets configuration depending on a request URI.即:根据请求的URI来设置具体配置,比如:
location ^~ /images/ {
[ configuration ]
}
该配置表示当uri中包括/images/时,就会被匹配,实际上不止要包括/images/,并且还要以/images/开头,因为它的前面有^~修饰符,该修饰符表示要以它后面指定的字符串开头。
location指令的规则
上面举了个栗子,这里详细说规则,首先说一下uri,uri是指url中的除去协议和域名及参数后,剩下的部分,比如请求的url为:http://www.test.com/test/index.php?page=1 ,则uri为:/test/index.php。
修饰符有以下四个,用于修饰它后面的URI:
=表示精确匹配,也就是uri要完全跟=号后面的值相同;
^~表示URI 以某个常规字符串开头,不是正则匹配;
~表示区分大小写正则匹配;
~*表示不区分大小写正则匹配。
location匹配原则:
1. 用所有的前缀字符串测试 URI;
2. 等号=定义了前缀字符串和 URI 的精确匹配关系。如果找到了这个精确匹配,则停止;
3. 查找。
4. 如果^~修饰符预先匹配到最长的前缀字符串,则不检查正则表达式;
5. 存储最长的匹配前缀字符串;
6. 用正则表达式测试 URI;
7. 匹配到第一个正则表达式后停止查找,使用对应的 location;
8. 如果没有匹配到正则表达式,则使用之前存储的前缀字符串对应的 location。
测试nginx配置:
server {
listen 80;
server_name www.test.com;
charset utf-8;
default_type text/html;
root /Users/bruce/www/personal/test;
access_log /usr/local/var/log/nginx/www.test.com.access.log;
error_log /usr/local/var/log/nginx/www.test.com.error.log;
autoindex on;
autoindex_exact_size off;
autoindex_format html;
autoindex_localtime on;
location = / {
return 502 "规则A\n";
}
location = /login {
return 502 "规则B\n";
}
location ^~ /static/ {
return 502 "规则C\n";
}
location ^~ /static/files {
return 502 "规则D\n";
}
location ~ \.(gif|jpg|png|js|css)$ {
return 502 "规则E\n";
}
location ~* \.PNG$ {
return 502 "规则F\n";
}
location /img {
return 502 "规则G\n";
}
location / {
return 502 "规则H\n";
}
location ~ \.php {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi.conf;
}
}
在hosts文件中添加域名解析:
127.0.0.1 www.test.com
另外,保证root、access_log、error_log三个指令指向的路径存在并且具有可访问权限,只要目录存在即可,目录里无需放任何文件。
鉴于一般人可能没装echo模块,所以我使用了return 502方式,如果你编译了echo模块,那么你可以把return 502换成echo即可,并且用echo的时候后面的\n还可以去掉,而用return 502如果后面没有\n,用curl访问则会多一个%,我加\n就是为了去掉这个百分号。
测试时,建议使用curl测试,不要用浏览器,因为用浏览器的话,测试访问图片时,浏览器会自动显示图片,虽然图片并不存在,但浏览器还是会显示一个黑色界面表示这是显示图片,而用curl就没这个问题,curl不用参数,直接curl http://xxxx.html即可,比如:
curl http://www.test.com/a.png
以下为测试url及结果说明:
访问根目录/,比如 http://www.test.com/或http://www.test.com 将匹配规则A,实际上http://www.test.com/会跳转到http://www.test.com。
访问 http://www.test.com/login 将匹配规则B, http://www.test.com/register则匹配 规则H。
访问http://www.test.com/static/a.html将匹配规则C。
访问 http://www.test.com/static/files/a.html 将匹配规则D ,虽然规则C也能匹配到,但因为最大匹配原则,最终选中了规则D。你可以测试下,去掉规则D,则当前URL会匹配上 规则C 。
访问 http://www.test.com/a.png , 将匹配规则E和规则F,但是规则E顺序优先,规则F不起作用,而http://www.test.com/static/c.png则优先匹配到规则C。
访问http://www.test.com/a.PNG 则匹配规则E,而不会匹配规则D,因为规则E不区分大小写。
访问http://www.test.com/img/a.gif会匹配上规则E ,虽然规则G也可以匹配上,但是因为正则匹配优先,而忽略了规则G 。
访问http://www.test.com/img/a.tiff 会匹配上规则G。
访问http://www.test.com/category/id/1111因为以上规则都不匹配,则最终匹配到规则H 。
if指令的使用规则
if指令属于ngx_http_rewrite_module(即rewrite模块),if必须写在serve里面r或location里面。if 的条件可能是以下任何一种情况:
变量名:如果变量值是空字符串或“0”则为 FALSE。注意,在 1.0.1 版本之前,任何以“0”开头的字符串都会被当做 FALSE。
使用=和!=的变量跟字符串的比较(注意,它并不像编程语言那样用两个==号来判断是否相等,而是用一个=号,加个感叹号就是不等于,并且字符串不需要用引号引起来,当然引起来也可以)。
使用~(区分大小写匹配)和~*(不区分大小写匹配)运算符将变量与正则表达式匹配。正则表达式可以包含捕获,之后可以通过$1到$9这几个变量名重复使用。!~和!~*用作不匹配运算符。如果正则表达式包含}或;字符,则整个表达式应该用单引号或双引号括起来。
-f和!-f用来判断是否存在文件(f:file)
-d和!-d用来判断是否存在目录(d:directory)
-e和!-e用来判断是否存在文件或目录(e:exists)
-x和!-x用来判断文件是否可执行(x:execute)
if指令测试配置:
注意if跟后面的括号一定要有一个空格,否则报错,但右括号(与左花括号{之间可以不用空格。
server {
listen 80;
server_name www.test.com;
charset utf-8;
default_type text/html;
root /Users/bruce/www/personal/test;
access_log /usr/local/var/log/nginx/www.test.com.access.log;
error_log /usr/local/var/log/nginx/www.test.com.error.log;
autoindex on;
autoindex_exact_size off;
autoindex_format html;
autoindex_localtime on;
location / {
# 如果用户代理 User-Agent 包含"chrome",rewrite 请求到/chrome/目录下。通过正则匹配的捕获可以用 $1/$2 等使用
if ($http_user_agent ~ Chrome) {
rewrite ^([^/]*)$ /chrome$1 break;
}
# 如果cookie匹配正则,设置变量$id等于匹配到的正则部分
if ($http_cookie ~* "id=([^;]+)(?:;|$)") {
set $id $1;
#为了证明是否设置成功,这里打印一下
#return 502 $id;
}
# 如果请求方法为 POST,则返回状态 405(Method not allowed)
if ($request_method = POST) {
return 405;
}
# 如果请求的文件存在,则开启缓存,并通过 break 停止后面的检查
if (-f $request_filename) {
expires max;
break;
}
# 如果请求的文件、目录或符号链接都不存在,则用 rewrite 在 URI 头部添加 /index.php
if (!-e $request_filename) {
echo $request_filename;
rewrite ^/(.*)$ /index.php break;
}
}
location ~ \.php {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi.conf;
}
}
以上配置不需要先注释其他if只留一个,全部一起测试就可以,注意如果你没有cookie,可以用Edit ThiscookieChrome扩展自己添加一个cookieid=10010用于测试,测试cookie那一块可以把return 502那个注释打开,否则无法测试出是否进入。
test目录的结构如下:
test
├── chrome
│ └── index.html
└── index.php
return、rewrite 和 try_files 指令
NGINX rewrite的两个通用指令是return和rewrite,而try_files指令可以将请求定向到应用程序服务器。
return指令
return指令简单高效,建议尽量使用return,而不是rewrite。return指令放在 server 或 location 上下文中。语法很简单:
return code [text];
return code URL;
return URL;
将客户重定向到一个新域名的示例:
server {
listen 80;
listen 443 ssl;
server_name www.old-name.com;
return 301 $scheme://www.new-name.com$request_uri;
}
上面代码中,listen 指令表明server 块同时用于 HTTP 和 HTTPS 流量。server_name指令匹配包含域名www.old-name.com的请求。return 指令告诉 Nginx 停止处理请求,直接返回 301 (Moved Permanently) 代码和指定的重写过的 URL 到客户端。$scheme 是协议(HTTP 或 HTTPS),$request_uri是包含参数的完整的URI。
对于 3xx 系列响应码,url 参数定义了新的(重写过的)URL:
return (301 | 302 | 303 | 307) url;
对于其他响应码,可以选择定义一个出现在响应正文中的文本字符串(HTTP 代码的标准文本,例如 404 的 Not Found,仍包含在标题中)。文本可以包含 NGINX 变量。
return (1xx | 2xx | 4xx | 5xx) ["text"];
例如,在拒绝没有有效身份验证令牌的请求时,此指令可能适用:
return 401 "Access denied because token is expired or invalid";
rewrite指令
rewrite 规则会改变部分或整个用户请求中的 URL,主要有两个用途:
– 通知客户端,请求的资源已经换地方了。例如网站改版后添加了 www 前缀,通过 rewrite 规则可以将所有请求导向新站点。
– 控制 Nginx 中的处理流程。例如当需要动态生成内容时,将请求转发到应用程序服务器。try_files 指令经常用于这个目的。
但是,如果需要测试 URL 之间更复杂的区别,或者要从原始 URL 中捕获的元素没有对应的 NGINX 变量,或者更改或添加路径中的元素(例如各大 PHP 框架常用的 index.php 入口文件),该怎么办? 可以使用 rewrite 指令。
rewrite 指令放在 server 或 location 上下文中。语法很简单:
rewrite regex URL [flag];
第一个参数 regex 是正则表达式。
flag 标志位
last 停止处理当前的ngx_http_rewrite_module指令集,并开始对匹配更改后的 URI 的新 location 进行搜索(再从 server 走一遍匹配流程)。此时对于当前 server 或 location 上下文,不再处理 ngx_http_rewrite_module 重写模块的指令。相当于Apache里的[L]标记。
break 终止匹配, 不再匹配后面的规则
redirect 返回包含 302 代码的临时重定向,地址栏会显示跳转后的地址,在替换字符串不以http://、https://或$scheme开头时使用。
permanent 返回包含 301 代码的永久重定向。
last和break就相当于php里的continue和break。
rewrite 指令只能返回代码 301 或 302。要返回其他代码,需要在 rewrite 指令后面包含 return 指令。
rewrite 指令不一定会暂停 NGINX 对请求的处理,因为它不一定会发送重定向到客户端。除非明确指出(使用 flag 或 URL 的语法)你希望 NGINX 停止处理或发送重定向,否则它将在整个配置中运行,查找在重写模块中定义的指令(break、if、return、rewrite 和 set),并按顺序处理。如果重写的 URL 与 Rewrite 模块中的后续指令匹配,NGINX 会对重写的 URL 执行指定的操作(通常会重新写入)。
这是复杂的地方,必须仔细计划指令顺序以获得期望的结果。例如,如果原始 location 块和其中的 NGINX 重写规则与重写的 URL 匹配,NGINX 可以进入一个循环,Nginx 默认限制循序最大 10 次。
下面是使用 rewrite 指令的 NGINX 重写规则的示例。它匹配以字符串 /download 开头的 URL,然后用 /mp3/ 替换在路径稍后的某个位置包含的 /media/ 或 /audio/ 目录,并添加适当的文件扩展名 .mp3 或 .ra。$1和$2变量捕获不变的路径元素。例如,/download/cdn-west/media/file1 变为 /download/cdn-west/mp3/file1.mp3。如果文件名上有扩展名(例如.flv),表达式会将其剥离并用.mp3替换。
server {
# ...
rewrite ^(/download/.*)/media/(\w+)\.?.*$ $1/mp3/$2.mp3 last;
rewrite ^(/download/.*)/audio/(\w+)\.?.*$ $1/mp3/$2.ra last;
return 403;
# ...
}
可以将 flag 添加到重写指令来控制处理流程。示例中的 last 告诉 NGINX 跳过当前服务器或位置块中的任何后续 ngx_http_rewrite_module 重写模块的指令,并开始搜索与重写的 URL 匹配的新位置。
这个例子中的最后一个 return 指令意味着如果 URL 不匹配任何一个 rewrite 指令,将返回给客户端 403 代码。
try_files 指令
try_files 指令也放在 server 或 location 上下文中。语法很简单:
try_files file ... uri;
try_files 指令的参数是一个或多个文件或目录的列表,以及最后面的 URI 参数。
Nginx 会按顺序检查文件及目录是否存在(根据 root 和 alias 指令设置的参数构造完整的文件路径),并用找到的第一个文件提供服务。在元素名后面添加斜杠 / 表示这个是目录。如果文件和目录都不存在,Nginx 会执行内部重定向,跳转到命令的最后一个 uri 参数定义的 URI 中。
要想 try_files 指令工作,必须定义一个 location 块捕捉内部重定向。最后一个参数可以是命名过的 location,由初始符号(@)指示。
try_files 指令通常使用 $uri 变量,表示 URL 中域名之后的部分。
下面示例中,如果客户端请求的文件不存在,Nginx 会响应一个默认的 GIF 文件。假设客户请求“http://www.domain.com/images/image1.gif”,Nginx 会首先通过用于这个 location 的 root 和 alias 指令,在本地目录中查找这个文件。如果“image1.gif”文件不存在,Nginx 会查找“image1.gif/”目录,如果都不存在,会重定向到“/images/default.gif”。这个值精确匹配后面的 location 指令,因此处理过程停止,Nginx 返回这个文件,并标注其缓存 30 秒。
location /images/ {
try_files $uri $uri/ /images/default.gif;
}
location = /images/default.gif {
expires 30s;
}
try_files常用到的变量:
$args 请求url中?后面的参数(不包括问号本身)
$is_args 如果$args不为空,则$is_args就是一个?号,如果$is_args为空,则$is_args也为空字符串,所以你会经常看见有这样的写法:
try_files $uri $uri/ /index.php$is_args$args;
而有些人会写成这样:
try_files $uri $uri/ /index.php?$args;
其实第二种写法肯定是不好的,因为万一$args为空,那么就留下了一个无用的问号,而用$is_args则能避免这个问题。
$query_string 与$args相同。
$document_root root指令指定的值。
$request_filename 当前连接请求的文件路径,由root或alias指令与URI请求生成(不包住参数)。
$request_uri 原始请求uri(即url中除去协议和域名的部分,比如:http://127.0.0.1/index.php的uri即为/index.php)。
nginx官方文档中说明的内置变量:http://nginx.org/en/docs/http/ngx_http_core_module.html#location
在nginx.org点击右侧的documentation
然后搜索:Modules reference,找到ngx_http_core_module,点进去(因为我们配置的是http服务器,所以我们需要的所有指令都在这个模块里面)
然后搜索:Embedded Variables,点进去,然后你就可以看到所有nginx http模块的的内置变量了:
Embedded Variables
The ngx_http_core_module module supports embedded variables with names matching the Apache Server variables. First of all, these are variables representing client request header fields, such as $http_user_agent, $http_cookie, and so on. Also there are other variables:
$arg_name argument name in the request line
$args arguments in the request line
$binary_remote_addr client address in a binary form, value’s length is always 4 bytes for IPv4 addresses or 16 bytes for IPv6 addresses
$body_bytes_sent number of bytes sent to a client, not counting the response header; this variable is compatible with the “%B” parameter of the mod_log_config Apache module
$bytes_sent number of bytes sent to a client (1.3.8, 1.2.5)
$connection connection serial number (1.3.8, 1.2.5)
$connection_requests current number of requests made through a connection (1.3.8, 1.2.5)
$content_length “Content-Length” request header field
$content_type “Content-Type” request header field
$cookie_name the name cookie
$document_root root or alias directive’s value for the current request
$document_uri same as $uri
$host in this order of precedence: host name from the request line, or host name from the “Host” request header field, or the server name matching a request
$hostname host name
$http_name arbitrary request header field; the last part of a variable name is the field name converted to lower case with dashes replaced by underscores
$https “on” if connection operates in SSL mode, or an empty string otherwise
$is_args “?” if a request line has arguments, or an empty string otherwise
$limit_rate setting this variable enables response rate limiting; see limit_rate
$msec current time in seconds with the milliseconds resolution (1.3.9, 1.2.6)
$nginx_version nginx version
$pid PID of the worker process
$pipe “p” if request was pipelined, “.” otherwise (1.3.12, 1.2.7)
$proxy_protocol_addr client address from the PROXY protocol header, or an empty string otherwise (1.5.12) .The PROXY protocol must be previously enabled by setting the proxy_protocol parameter in the listen directive.
$proxy_protocol_port client port from the PROXY protocol header, or an empty string otherwise (1.11.0)
The PROXY protocol must be previously enabled by setting the proxy_protocol parameter in the listen directive.
$query_string same as $args
$realpath_root an absolute pathname corresponding to the root or alias directive’s value for the current request, with all symbolic links resolved to real paths
$remote_addr client address
$remote_port client port
$remote_user user name supplied with the Basic authentication
$request full original request line
$request_body request body
The variable’s value is made available in locations processed by the proxy_pass, fastcgi_pass, uwsgi_pass, and scgi_pass directives when the request body was read to a memory buffer.
$request_body_file name of a temporary file with the request body
At the end of processing, the file needs to be removed. To always write the request body to a file, client_body_in_file_only needs to be enabled. When the name of a temporary file is passed in a proxied request or in a request to a FastCGI/uwsgi/SCGI server, passing the request body should be disabled by the proxy_pass_request_body off, fastcgi_pass_request_body off, uwsgi_pass_request_body off, or scgi_pass_request_body off directives, respectively.
$request_completion “OK” if a request has completed, or an empty string otherwise
$request_filename file path for the current request, based on the root or alias directives, and the request URI
$request_id unique request identifier generated from 16 random bytes, in hexadecimal (1.11.0)
$request_length request length (including request line, header, and request body) (1.3.12, 1.2.7)
$request_method request method, usually “GET” or “POST”
$request_time request processing time in seconds with a milliseconds resolution (1.3.9, 1.2.6); time elapsed since the first bytes were read from the client
$request_uri full original request URI (with arguments)
$scheme request scheme, “http” or “https”
$sent_http_name arbitrary response header field; the last part of a variable name is the field name converted to lower case with dashes replaced by underscores
$sent_trailer_name arbitrary field sent at the end of the response (1.13.2); the last part of a variable name is the field name converted to lower case with dashes replaced by underscores
$server_addr an address of the server which accepted a request
Computing a value of this variable usually requires one system call. To avoid a system call, the listen directives must specify addresses and use the bind parameter.
$server_name name of the server which accepted a request
$server_port port of the server which accepted a request
$server_protocol request protocol, usually “HTTP/1.0”, “HTTP/1.1”, or “HTTP/2.0”
$status response status (1.3.2, 1.2.2)
$tcpinfo_rtt,$tcpinfo_rttvar, $tcpinfo_snd_cwnd, $tcpinfo_rcv_space
information about the client TCP connection; available on systems that support the TCP_INFO socket option
$time_iso8601 local time in the ISO 8601 standard format (1.3.12, 1.2.7)
$time_local local time in the Common Log Format (1.3.12, 1.2.7)
$uri current URI in request, normalized
The value of $uri may change during request processing, e.g. when doing internal redirects, or when using index files.
其他的可参考:Nginx 基本功能 – 将 Nginx 配置为 Web 服务器(HTTP Server)
location指令要放在server模块里面,语法如下:
server{
location 修饰符 URI {
[具体配置]
}
}
location指令是干嘛用的?
根据官方文档,location的作用是:Sets configuration depending on a request URI.即:根据请求的URI来设置具体配置,比如:
location ^~ /images/ {
[ configuration ]
}
该配置表示当uri中包括/images/时,就会被匹配,实际上不止要包括/images/,并且还要以/images/开头,因为它的前面有^~修饰符,该修饰符表示要以它后面指定的字符串开头。
location指令的规则
上面举了个栗子,这里详细说规则,首先说一下uri,uri是指url中的除去协议和域名及参数后,剩下的部分,比如请求的url为:http://www.test.com/test/index.php?page=1 ,则uri为:/test/index.php。
修饰符有以下四个,用于修饰它后面的URI:
=表示精确匹配,也就是uri要完全跟=号后面的值相同;
^~表示URI 以某个常规字符串开头,不是正则匹配;
~表示区分大小写正则匹配;
~*表示不区分大小写正则匹配。
location匹配原则:
1. 用所有的前缀字符串测试 URI;
2. 等号=定义了前缀字符串和 URI 的精确匹配关系。如果找到了这个精确匹配,则停止;
3. 查找。
4. 如果^~修饰符预先匹配到最长的前缀字符串,则不检查正则表达式;
5. 存储最长的匹配前缀字符串;
6. 用正则表达式测试 URI;
7. 匹配到第一个正则表达式后停止查找,使用对应的 location;
8. 如果没有匹配到正则表达式,则使用之前存储的前缀字符串对应的 location。
测试nginx配置:
server {
listen 80;
server_name www.test.com;
charset utf-8;
default_type text/html;
root /Users/bruce/www/personal/test;
access_log /usr/local/var/log/nginx/www.test.com.access.log;
error_log /usr/local/var/log/nginx/www.test.com.error.log;
autoindex on;
autoindex_exact_size off;
autoindex_format html;
autoindex_localtime on;
location = / {
return 502 "规则A\n";
}
location = /login {
return 502 "规则B\n";
}
location ^~ /static/ {
return 502 "规则C\n";
}
location ^~ /static/files {
return 502 "规则D\n";
}
location ~ \.(gif|jpg|png|js|css)$ {
return 502 "规则E\n";
}
location ~* \.PNG$ {
return 502 "规则F\n";
}
location /img {
return 502 "规则G\n";
}
location / {
return 502 "规则H\n";
}
location ~ \.php {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi.conf;
}
}
在hosts文件中添加域名解析:
127.0.0.1 www.test.com
另外,保证root、access_log、error_log三个指令指向的路径存在并且具有可访问权限,只要目录存在即可,目录里无需放任何文件。
鉴于一般人可能没装echo模块,所以我使用了return 502方式,如果你编译了echo模块,那么你可以把return 502换成echo即可,并且用echo的时候后面的\n还可以去掉,而用return 502如果后面没有\n,用curl访问则会多一个%,我加\n就是为了去掉这个百分号。
测试时,建议使用curl测试,不要用浏览器,因为用浏览器的话,测试访问图片时,浏览器会自动显示图片,虽然图片并不存在,但浏览器还是会显示一个黑色界面表示这是显示图片,而用curl就没这个问题,curl不用参数,直接curl http://xxxx.html即可,比如:
curl http://www.test.com/a.png
以下为测试url及结果说明:
访问根目录/,比如 http://www.test.com/或http://www.test.com 将匹配规则A,实际上http://www.test.com/会跳转到http://www.test.com。
访问 http://www.test.com/login 将匹配规则B, http://www.test.com/register则匹配 规则H。
访问http://www.test.com/static/a.html将匹配规则C。
访问 http://www.test.com/static/files/a.html 将匹配规则D ,虽然规则C也能匹配到,但因为最大匹配原则,最终选中了规则D。你可以测试下,去掉规则D,则当前URL会匹配上 规则C 。
访问 http://www.test.com/a.png , 将匹配规则E和规则F,但是规则E顺序优先,规则F不起作用,而http://www.test.com/static/c.png则优先匹配到规则C。
访问http://www.test.com/a.PNG 则匹配规则E,而不会匹配规则D,因为规则E不区分大小写。
访问http://www.test.com/img/a.gif会匹配上规则E ,虽然规则G也可以匹配上,但是因为正则匹配优先,而忽略了规则G 。
访问http://www.test.com/img/a.tiff 会匹配上规则G。
访问http://www.test.com/category/id/1111因为以上规则都不匹配,则最终匹配到规则H 。
if指令的使用规则
if指令属于ngx_http_rewrite_module(即rewrite模块),if必须写在serve里面r或location里面。if 的条件可能是以下任何一种情况:
变量名:如果变量值是空字符串或“0”则为 FALSE。注意,在 1.0.1 版本之前,任何以“0”开头的字符串都会被当做 FALSE。
使用=和!=的变量跟字符串的比较(注意,它并不像编程语言那样用两个==号来判断是否相等,而是用一个=号,加个感叹号就是不等于,并且字符串不需要用引号引起来,当然引起来也可以)。
使用~(区分大小写匹配)和~*(不区分大小写匹配)运算符将变量与正则表达式匹配。正则表达式可以包含捕获,之后可以通过$1到$9这几个变量名重复使用。!~和!~*用作不匹配运算符。如果正则表达式包含}或;字符,则整个表达式应该用单引号或双引号括起来。
-f和!-f用来判断是否存在文件(f:file)
-d和!-d用来判断是否存在目录(d:directory)
-e和!-e用来判断是否存在文件或目录(e:exists)
-x和!-x用来判断文件是否可执行(x:execute)
if指令测试配置:
注意if跟后面的括号一定要有一个空格,否则报错,但右括号(与左花括号{之间可以不用空格。
server {
listen 80;
server_name www.test.com;
charset utf-8;
default_type text/html;
root /Users/bruce/www/personal/test;
access_log /usr/local/var/log/nginx/www.test.com.access.log;
error_log /usr/local/var/log/nginx/www.test.com.error.log;
autoindex on;
autoindex_exact_size off;
autoindex_format html;
autoindex_localtime on;
location / {
# 如果用户代理 User-Agent 包含"chrome",rewrite 请求到/chrome/目录下。通过正则匹配的捕获可以用 $1/$2 等使用
if ($http_user_agent ~ Chrome) {
rewrite ^([^/]*)$ /chrome$1 break;
}
# 如果cookie匹配正则,设置变量$id等于匹配到的正则部分
if ($http_cookie ~* "id=([^;]+)(?:;|$)") {
set $id $1;
#为了证明是否设置成功,这里打印一下
#return 502 $id;
}
# 如果请求方法为 POST,则返回状态 405(Method not allowed)
if ($request_method = POST) {
return 405;
}
# 如果请求的文件存在,则开启缓存,并通过 break 停止后面的检查
if (-f $request_filename) {
expires max;
break;
}
# 如果请求的文件、目录或符号链接都不存在,则用 rewrite 在 URI 头部添加 /index.php
if (!-e $request_filename) {
echo $request_filename;
rewrite ^/(.*)$ /index.php break;
}
}
location ~ \.php {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi.conf;
}
}
以上配置不需要先注释其他if只留一个,全部一起测试就可以,注意如果你没有cookie,可以用Edit ThiscookieChrome扩展自己添加一个cookieid=10010用于测试,测试cookie那一块可以把return 502那个注释打开,否则无法测试出是否进入。
test目录的结构如下:
test
├── chrome
│ └── index.html
└── index.php
return、rewrite 和 try_files 指令
NGINX rewrite的两个通用指令是return和rewrite,而try_files指令可以将请求定向到应用程序服务器。
return指令
return指令简单高效,建议尽量使用return,而不是rewrite。return指令放在 server 或 location 上下文中。语法很简单:
return code [text];
return code URL;
return URL;
将客户重定向到一个新域名的示例:
server {
listen 80;
listen 443 ssl;
server_name www.old-name.com;
return 301 $scheme://www.new-name.com$request_uri;
}
上面代码中,listen 指令表明server 块同时用于 HTTP 和 HTTPS 流量。server_name指令匹配包含域名www.old-name.com的请求。return 指令告诉 Nginx 停止处理请求,直接返回 301 (Moved Permanently) 代码和指定的重写过的 URL 到客户端。$scheme 是协议(HTTP 或 HTTPS),$request_uri是包含参数的完整的URI。
对于 3xx 系列响应码,url 参数定义了新的(重写过的)URL:
return (301 | 302 | 303 | 307) url;
对于其他响应码,可以选择定义一个出现在响应正文中的文本字符串(HTTP 代码的标准文本,例如 404 的 Not Found,仍包含在标题中)。文本可以包含 NGINX 变量。
return (1xx | 2xx | 4xx | 5xx) ["text"];
例如,在拒绝没有有效身份验证令牌的请求时,此指令可能适用:
return 401 "Access denied because token is expired or invalid";
rewrite指令
rewrite 规则会改变部分或整个用户请求中的 URL,主要有两个用途:
– 通知客户端,请求的资源已经换地方了。例如网站改版后添加了 www 前缀,通过 rewrite 规则可以将所有请求导向新站点。
– 控制 Nginx 中的处理流程。例如当需要动态生成内容时,将请求转发到应用程序服务器。try_files 指令经常用于这个目的。
但是,如果需要测试 URL 之间更复杂的区别,或者要从原始 URL 中捕获的元素没有对应的 NGINX 变量,或者更改或添加路径中的元素(例如各大 PHP 框架常用的 index.php 入口文件),该怎么办? 可以使用 rewrite 指令。
rewrite 指令放在 server 或 location 上下文中。语法很简单:
rewrite regex URL [flag];
第一个参数 regex 是正则表达式。
flag 标志位
last 停止处理当前的ngx_http_rewrite_module指令集,并开始对匹配更改后的 URI 的新 location 进行搜索(再从 server 走一遍匹配流程)。此时对于当前 server 或 location 上下文,不再处理 ngx_http_rewrite_module 重写模块的指令。相当于Apache里的[L]标记。
break 终止匹配, 不再匹配后面的规则
redirect 返回包含 302 代码的临时重定向,地址栏会显示跳转后的地址,在替换字符串不以http://、https://或$scheme开头时使用。
permanent 返回包含 301 代码的永久重定向。
last和break就相当于php里的continue和break。
rewrite 指令只能返回代码 301 或 302。要返回其他代码,需要在 rewrite 指令后面包含 return 指令。
rewrite 指令不一定会暂停 NGINX 对请求的处理,因为它不一定会发送重定向到客户端。除非明确指出(使用 flag 或 URL 的语法)你希望 NGINX 停止处理或发送重定向,否则它将在整个配置中运行,查找在重写模块中定义的指令(break、if、return、rewrite 和 set),并按顺序处理。如果重写的 URL 与 Rewrite 模块中的后续指令匹配,NGINX 会对重写的 URL 执行指定的操作(通常会重新写入)。
这是复杂的地方,必须仔细计划指令顺序以获得期望的结果。例如,如果原始 location 块和其中的 NGINX 重写规则与重写的 URL 匹配,NGINX 可以进入一个循环,Nginx 默认限制循序最大 10 次。
下面是使用 rewrite 指令的 NGINX 重写规则的示例。它匹配以字符串 /download 开头的 URL,然后用 /mp3/ 替换在路径稍后的某个位置包含的 /media/ 或 /audio/ 目录,并添加适当的文件扩展名 .mp3 或 .ra。$1和$2变量捕获不变的路径元素。例如,/download/cdn-west/media/file1 变为 /download/cdn-west/mp3/file1.mp3。如果文件名上有扩展名(例如.flv),表达式会将其剥离并用.mp3替换。
server {
# ...
rewrite ^(/download/.*)/media/(\w+)\.?.*$ $1/mp3/$2.mp3 last;
rewrite ^(/download/.*)/audio/(\w+)\.?.*$ $1/mp3/$2.ra last;
return 403;
# ...
}
可以将 flag 添加到重写指令来控制处理流程。示例中的 last 告诉 NGINX 跳过当前服务器或位置块中的任何后续 ngx_http_rewrite_module 重写模块的指令,并开始搜索与重写的 URL 匹配的新位置。
这个例子中的最后一个 return 指令意味着如果 URL 不匹配任何一个 rewrite 指令,将返回给客户端 403 代码。
try_files 指令
try_files 指令也放在 server 或 location 上下文中。语法很简单:
try_files file ... uri;
try_files 指令的参数是一个或多个文件或目录的列表,以及最后面的 URI 参数。
Nginx 会按顺序检查文件及目录是否存在(根据 root 和 alias 指令设置的参数构造完整的文件路径),并用找到的第一个文件提供服务。在元素名后面添加斜杠 / 表示这个是目录。如果文件和目录都不存在,Nginx 会执行内部重定向,跳转到命令的最后一个 uri 参数定义的 URI 中。
要想 try_files 指令工作,必须定义一个 location 块捕捉内部重定向。最后一个参数可以是命名过的 location,由初始符号(@)指示。
try_files 指令通常使用 $uri 变量,表示 URL 中域名之后的部分。
下面示例中,如果客户端请求的文件不存在,Nginx 会响应一个默认的 GIF 文件。假设客户请求“http://www.domain.com/images/image1.gif”,Nginx 会首先通过用于这个 location 的 root 和 alias 指令,在本地目录中查找这个文件。如果“image1.gif”文件不存在,Nginx 会查找“image1.gif/”目录,如果都不存在,会重定向到“/images/default.gif”。这个值精确匹配后面的 location 指令,因此处理过程停止,Nginx 返回这个文件,并标注其缓存 30 秒。
location /images/ {
try_files $uri $uri/ /images/default.gif;
}
location = /images/default.gif {
expires 30s;
}
try_files常用到的变量:
$args 请求url中?后面的参数(不包括问号本身)
$is_args 如果$args不为空,则$is_args就是一个?号,如果$is_args为空,则$is_args也为空字符串,所以你会经常看见有这样的写法:
try_files $uri $uri/ /index.php$is_args$args;
而有些人会写成这样:
try_files $uri $uri/ /index.php?$args;
其实第二种写法肯定是不好的,因为万一$args为空,那么就留下了一个无用的问号,而用$is_args则能避免这个问题。
$query_string 与$args相同。
$document_root root指令指定的值。
$request_filename 当前连接请求的文件路径,由root或alias指令与URI请求生成(不包住参数)。
$request_uri 原始请求uri(即url中除去协议和域名的部分,比如:http://127.0.0.1/index.php的uri即为/index.php)。
nginx官方文档中说明的内置变量:http://nginx.org/en/docs/http/ngx_http_core_module.html#location
在nginx.org点击右侧的documentation
然后搜索:Modules reference,找到ngx_http_core_module,点进去(因为我们配置的是http服务器,所以我们需要的所有指令都在这个模块里面)
然后搜索:Embedded Variables,点进去,然后你就可以看到所有nginx http模块的的内置变量了:
Embedded Variables
The ngx_http_core_module module supports embedded variables with names matching the Apache Server variables. First of all, these are variables representing client request header fields, such as $http_user_agent, $http_cookie, and so on. Also there are other variables:
$arg_name argument name in the request line
$args arguments in the request line
$binary_remote_addr client address in a binary form, value’s length is always 4 bytes for IPv4 addresses or 16 bytes for IPv6 addresses
$body_bytes_sent number of bytes sent to a client, not counting the response header; this variable is compatible with the “%B” parameter of the mod_log_config Apache module
$bytes_sent number of bytes sent to a client (1.3.8, 1.2.5)
$connection connection serial number (1.3.8, 1.2.5)
$connection_requests current number of requests made through a connection (1.3.8, 1.2.5)
$content_length “Content-Length” request header field
$content_type “Content-Type” request header field
$cookie_name the name cookie
$document_root root or alias directive’s value for the current request
$document_uri same as $uri
$host in this order of precedence: host name from the request line, or host name from the “Host” request header field, or the server name matching a request
$hostname host name
$http_name arbitrary request header field; the last part of a variable name is the field name converted to lower case with dashes replaced by underscores
$https “on” if connection operates in SSL mode, or an empty string otherwise
$is_args “?” if a request line has arguments, or an empty string otherwise
$limit_rate setting this variable enables response rate limiting; see limit_rate
$msec current time in seconds with the milliseconds resolution (1.3.9, 1.2.6)
$nginx_version nginx version
$pid PID of the worker process
$pipe “p” if request was pipelined, “.” otherwise (1.3.12, 1.2.7)
$proxy_protocol_addr client address from the PROXY protocol header, or an empty string otherwise (1.5.12) .The PROXY protocol must be previously enabled by setting the proxy_protocol parameter in the listen directive.
$proxy_protocol_port client port from the PROXY protocol header, or an empty string otherwise (1.11.0)
The PROXY protocol must be previously enabled by setting the proxy_protocol parameter in the listen directive.
$query_string same as $args
$realpath_root an absolute pathname corresponding to the root or alias directive’s value for the current request, with all symbolic links resolved to real paths
$remote_addr client address
$remote_port client port
$remote_user user name supplied with the Basic authentication
$request full original request line
$request_body request body
The variable’s value is made available in locations processed by the proxy_pass, fastcgi_pass, uwsgi_pass, and scgi_pass directives when the request body was read to a memory buffer.
$request_body_file name of a temporary file with the request body
At the end of processing, the file needs to be removed. To always write the request body to a file, client_body_in_file_only needs to be enabled. When the name of a temporary file is passed in a proxied request or in a request to a FastCGI/uwsgi/SCGI server, passing the request body should be disabled by the proxy_pass_request_body off, fastcgi_pass_request_body off, uwsgi_pass_request_body off, or scgi_pass_request_body off directives, respectively.
$request_completion “OK” if a request has completed, or an empty string otherwise
$request_filename file path for the current request, based on the root or alias directives, and the request URI
$request_id unique request identifier generated from 16 random bytes, in hexadecimal (1.11.0)
$request_length request length (including request line, header, and request body) (1.3.12, 1.2.7)
$request_method request method, usually “GET” or “POST”
$request_time request processing time in seconds with a milliseconds resolution (1.3.9, 1.2.6); time elapsed since the first bytes were read from the client
$request_uri full original request URI (with arguments)
$scheme request scheme, “http” or “https”
$sent_http_name arbitrary response header field; the last part of a variable name is the field name converted to lower case with dashes replaced by underscores
$sent_trailer_name arbitrary field sent at the end of the response (1.13.2); the last part of a variable name is the field name converted to lower case with dashes replaced by underscores
$server_addr an address of the server which accepted a request
Computing a value of this variable usually requires one system call. To avoid a system call, the listen directives must specify addresses and use the bind parameter.
$server_name name of the server which accepted a request
$server_port port of the server which accepted a request
$server_protocol request protocol, usually “HTTP/1.0”, “HTTP/1.1”, or “HTTP/2.0”
$status response status (1.3.2, 1.2.2)
$tcpinfo_rtt,$tcpinfo_rttvar, $tcpinfo_snd_cwnd, $tcpinfo_rcv_space
information about the client TCP connection; available on systems that support the TCP_INFO socket option
$time_iso8601 local time in the ISO 8601 standard format (1.3.12, 1.2.7)
$time_local local time in the Common Log Format (1.3.12, 1.2.7)
$uri current URI in request, normalized
The value of $uri may change during request processing, e.g. when doing internal redirects, or when using index files.
其他的可参考:Nginx 基本功能 – 将 Nginx 配置为 Web 服务器(HTTP Server)