Nginx(发音同engine x)是一个异步框架的 Web服务器,也可以用作反向代理,负载平衡器 和 HTTP缓存。

平时在作为一个前端,在工作里面需要使用的Nginx的时候还是挺多,也用不到到多高深,能启动,做个反向代理,解决跨域问题,静态资源的服务器,能关闭,也就能满足大部分需求了。负载均衡什么听起来很高端,对于Nginx来说,你配置个低配版的负载均衡还是很容易的。接下来就大概说说Nginx的配置。

基本配置

Nginx 的使用基本都是做一些配置项,下面来介绍 Nginx 相关的配置。

Nginx 的配置文件在Nginx/conf/Nginx.conf,打开它后可以看到有一些基本的配置模版。

基本上作为一个前端来说其他的配置都用不上。查看Nginx配置的时候,只用关心配置sever 括号里面的内容就可以了。

Nginx的基本语法

  1. 属性名 [空格] 属性值 分号
  2. #后面的内容表示注释
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
server {
# Nginx 监听端口号
listen 80;

# 服务器的名字,默认为 localhost,你也可以写成 aotu.jd.com,这样子就可以通过 aotu.jd.com 来访问
server_name localhost;

# 代码放置的根目录
root /var/www/;
# 编码
charset utf-8;

location / {
# index 字段声明了解析的后缀名的先后顺序
# 下面匹配到/的时候默认找后缀名为 php 的文件,找不到再找 html,再找不到就找 htm
index index.php index.html index.htm;
# 自动索引
autoindex on;
}

# 404 页面跳转到 404.html,相对于上面的 root 目录
error_page 404/404.html;
# 403 页面跳转到 403.html,相对于上面的 root 目录
error_page 403/403.html;
# 50x 页面跳转到 50x.html
error_page 500 502 503 504/50x.html;
location = /50x.html {
root html;
}
}

说明:Nginx 的配置项写法是第一个是配置项名称,其后面空格接值,最后以分号结束。上面的配置的意思就是:访问 http://localhost 的时候会在 /var/www/ 下面找 index.php 文件,如果没有找到就找 index.html,如果再没有找到那就找 index.htm,如果还是没有找到的话就 404 跳转到 404.html,如果你刚好将 /var/www/ 设置为 root 用户访问的话,那么就会直接无访问权限 403 跳转到 403.html。

路由匹配规则

location指令的语法

location [=|~|~*|^~|@] /uri/ { … } 或 location @name { … }

location指令分为两种匹配模式

  1. 普通字符串匹配:以=开头或开头无引导字符(~)的规则
  2. 正则匹配:以~或~*开头表示正则匹配,~*表示正则不区分大小写
  • = 严格匹配。如果请求匹配这个location,那么将停止搜索并立即处理此请求
  • ~ 区分大小写匹配(可用正则表达式)
  • ~* 不区分大小写匹配(可用正则表达式)
  • !~ 区分大小写不匹配
  • !~* 不区分大小写不匹配
  • ^~ 如果把这个前缀用于一个常规字符串,那么告诉Nginx如果路径匹配那么不测试正则表达式表示普通字符匹配,如果该选项匹配,只匹配该选项,不匹配别的选项,一般用来匹配目录。

location匹配url的规则

Nginx收到一个请求后,会截取请求的uri部份,去搜索所有location指令中定义的uri匹配模式。在server模块中可以定义多个location指令来匹配不同的url请求,多个不同location配置的URI匹配模式。

总体的匹配原则是:先匹配普通字符串模式,再匹配正则模式。只识别URI部份,例如请求为:/test/abc/user.do?name=xxxx 一个请求过来后,Nginx匹配这个请求的流程如下: 1. 先查找是否有=开头的精确匹配,如:location = /test/abc/user.do { … } 2. 再查找普通匹配,以 最大前缀 为原则,如有以下两个location,则会匹配后一项 location /test/ { … } location /test/abc { … } 3. 匹配到一个普通格式后,搜索并未结束,而是暂存当前匹配的结果,并继续搜索正则匹配模式 4. 所有正则匹配模式location中找到第一个匹配项后,就以此项为最终匹配结果 所以正则匹配项匹配规则,受定义的前后顺序影响,但普通匹配模式不会 5. 如果未找到正则匹配项,则以3中缓存的结果为最终匹配结果 6. 如果一个匹配都没搜索到,则返回404

举几个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
location = /                 { 规则1 }
location / { 规则2 }
location /static/ { 规则3 }
location ^~ /images/ { 规则4 }
location ~* \.(jpg|png)$ { 规则5 }

# 访问
# / -> 规则1
# /api -> 规则2
# /static/index.html -> 规则3
# /static/a.png -> 规则5
# /images/a.html -> 规则4
# /images/a.png -> 规则4
# /a.png -> 规则5

说明:=/ { … }location / { … } 的差别:前一个是精确匹配,只响应/请求,所有/xxx或/xxx/xxxx类的请求都不会以前缀的形式匹配到它 ,后一个是只要以 / 为前缀的请求都会被匹配到。如:/abc/test/abc/test/abc/aaaa。前3个应该都没问题,第四个根据上面的匹配规则,/static/a.png先首先匹配到规则3(最大前缀原则),但是这是个普通匹配,所以还会继续的往下找,然后匹配到正则表达式规则5。第五,六个虽然是普通匹配,但是^~匹配到这里就已经结束了。匹配不到规则5。第七个也简单。

常见问题

alias与root的区别

root 实际访问文件路径会拼接URL中的路径 alias 实际访问文件路径不会拼接URL中的路径

1
2
3
location ^~ /sta/ {  
alias /usr/local/Nginx/html/static/;
}

请求:http://test.com/sta/sta1.html 实际访问:/usr/local/Nginx/html/static/sta1.html 文件

1
2
3
location ^~ /tea/ {  
root /usr/local/Nginx/html/;
}

请求:http://test.com/tea/tea1.html 实际访问:/usr/local/Nginx/html/tea/tea1.html 文件

last 和brack关键字的区别

(1)last 和 break 当出现在location 之外时,两者的作用是一致的没有任何差异

(2)last 和 break 当出现在location 内部时:

last 使用了last 指令,rewrite 后会跳出location 作用域,重新开始再走一次刚才的行为 break 使用了break 指令,rewrite后不会跳出location 作用域,它的生命也在这个location中终结

根据设备访问移动端还是pc端。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
server {
set $mobile_rewrite do_not_perform;
if ($http_user_agent ~* "(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino") {
set $mobile_rewrite perform;
}
if ($http_user_agent ~* "^(1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-)") {
set $mobile_rewrite perform;
}
if ($http_cookie ~ 'gotopc=true') {
set $mobile_rewrite do_not_perform;
}
location = / {
if ($mobile_rewrite = perform) {
root /data/www/html/phone;
}
if($mobile_rewrite != perform){
root /data/www/html/pc;
}
index index.html;
}
}

根据用户请求的UA判断用户的的访问设备,访问不用的静态文件。

前端单页应用history路由配置

1
2
3
location / {
try_files $uri $uri/ /index.html;
}

其作用是按顺序检查文件是否存在,返回第一个找到的文件或文件夹(结尾加斜线表示为文件夹),如果所有的文件或文件夹都找不到,会进行一个内部重定向到最后一个参数。

需要注意的是,只有最后一个参数可以引起一个内部重定向,之前的参数只设置内部URI的指向。最后一个参数是回退URI且必须存在,否则会出现内部500错误。命名的location也可以使用在最后一个参数中。

临时跳转

1
2
3
location /v1/ {
return 302 http://aotu.jd.com/v2/;
}

有时候应用升级了,但是还是有用户会访问 v1 版本,为了方便过渡,可以使用临时转跳的方式,让 v1 的用户跳转到 v2 上。

反向代理

1
2
3
4
5
6
7
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://localhost:8080;
}
}

比如你的服务器只开放80端口出去,但是你的起的node服务是在8080端口,那么你就用的上Nginx的反向代理功能。当用户访问你的服务器80端口的时候,Nginx会把请求转发到8080端口,经过8080端口服务的处理请求,把响应又转发给Nginx,Nginx再把这个响应返回给用户,但是看起来好像是服务器的80端口的服务响应了请求一样。

参考链接