1、引言
Nginx拥有大量官方发布的模块和第三方模块,这些已有的模块可以帮助我们实现Web服务器上很多的功能。使用这些模块时,仅仅需要增加、修改一些配置项即可。 因此,本章的目的是熟悉Nginx的配置文件, 包括配置文件的语法格式、 运行所有Nginx服务必须具备的基础配置以及使用HTTP核心模块配置静态Web服务器的方法,最后还会介绍反向代理服务器。
2、Nginx进程模型
详细解释Nginx进程模型,优点,以及为什么这样做,后期将通过代码的方式去观察到低是如何实现的这些高效?
1、简单介绍模型
在正式提供服务的产品环境下,部署Nginx时都是使用一个master进程来管理多个worker进程,一般情况下, worker进程的数量与服务器上的CPU核心数相等。 每一个worker进程都是繁忙的, 它们在真正地提供互联网服务, master进程则很“清闲”, 只负责监控管理worker进程。 worker进程之间通过共享内存、 原子操作等一些进程间通信机制来实现负载均衡等功能。
nginx采用多进程的方式运行。nginx在启动后,会有一个master进程和多个worker进程。master进程主要用来管理worker进程,包含:接收来自外界的信号;向各worker进程发送信号;监控worker进程的运行状态;当worker进程退出后(异常情况下产生coredump),会自动重新启动新的worker进程。所以worker进程的权限要小于或等于master进程,这样master进程才可以完全地管理worker进程。而基本的网络事件,则是放在worker进程中来处理了。多个worker进程之间是对等的,他们同等竞争来自客户端的请求,各进程互相之间是独立的。一个请求,只可能在一个worker进程中处理,一个worker进程,不可能处理其它进程的请求。worker进程的个数是可以设置的,一般我们会设置与机器cpu核数一致,这里面的原因与nginx的进程模型以及事件处理模型是分不开的。
Nginx是支持单进程(master进程)提供服务(这就和低版本的Libevent一样)了, 那么为什么产品环境下要按照masterworker方式配置同时启动多个进程呢? 原因有下面两点:
- 由于master进程不会对用户请求提供服务,只用于管理真正提供服务的worker进程,所以master进程可以是唯一的,它仅专注于自己的纯管理工作,为管理员提供命令行服务,包括诸如启动服务、 停止服务、 重载配置文件、平滑升级程序等。
- 多个worker进程处理互联网请求不但可以提高服务的健壮性(一个worker进程出错
后, 其他worker进程仍然可以正常提供服务),最重要的是,这样可以充分利用现在常见的SMP多核架构, 从而实现微观上真正的多核并发处理。因此用一个进程(master进程)来处理互联网请求肯定是不合适的。一个worker进程可以同时处理的请求数只受限于内存大小(通过epoll监听), 而且在架构设计上,不同的worker进程之间处理并发请求时几乎没有同步锁的限制, worker进程通常不会进入睡眠状态(非阻塞socket,仅仅可能陷入epoll等待而已),因此,当Nginx上的进程数与CPU核心数相等时(最好每一个worker进程都绑定特定的CPU核心),进程间切换的代价是最小。
一个请求,只可能在一个worker进程中处理,一个worker进程,不可能处理其它进程的请求。每个worker
进程里面,可以处理多个连接,worker进程竞争地accept
后,将连接的accept_fd加入其epoll里面。然后当epoll返回可读可写的fd时候,循环处理多个准备好的事件即可,这样并没有带来任何额外的上下文切换,事件处理非常的轻量级,只是占用了一些内存空间即可。所以在Nginx配置的时候, 工作进程个数一般设定为cpu的核数,在这里就很容易理解了,更多的worker数,只会导致进程来竞争cpu资源了,从而带来不必要的上下文切换。这点和Libevent思路基本相似,通过epoll实现单进程处理高并发请求。
2、worker进程处理请求
worker进程又是如何处理请求的呢?我们前面有提到,worker进程之间是平等的,每个进程,处理请求的机会也是一样的。当我们提供80端口的http服务时,一个连接请求过来,每个进程都有可能处理这个连接,怎么做到的呢?首先,每个worker进程都是从master进程fork过来,在master进程里面,先建立好需要listen的socket(listenfd)之后,然后再fork出多个worker进程。所有worker进程的listenfd会在新连接到来时变得可读,为保证只有一个进程处理该连接,所有worker进程在注册listenfd读事件前抢accept_mutex,抢到互斥锁的那个进程注册listenfd读事件,在读事件里调用accept接受该连接。当一个worker进程在accept这个连接之后,就开始读取请求,解析请求,处理请求,产生数据后,再返回给客户端,最后才断开连接,这样一个完整的请求就是这样的了。我们可以看到,一个请求,完全由worker进程来处理,而且只在一个worker进程中处理。
3、每个worker为何可以处理高并发
总体思路就是连接请求到来,多个work进程竞争抢占accept
并将fd加入epoll,一个work通过epoll管理多个连接。几乎不涉及上下文切换带来的开销,全部都靠epoll实现。
nginx采用多worker的方式来处理请求,每个worker里面只有一个主线程,那能够处理的并发数很有限啊,多少个worker就能处理多少个并发,何来高并发呢?nginx可以采用异步非阻塞的方式来解决高并发问题。
nginx采用了异步非阻塞的方式(IO复用机制)来处理请求,也就是说,nginx是可以同时处理成千上万个请求的。想想apache的常用工作方式(apache也有异步非阻塞版本,但因其与自带某些模块冲突,所以不常用),每个请求会独占一个工作线程,当并发数上到几千时,就同时有几千的线程在处理请求了。这对操作系统来说,是个不小的挑战,线程带来的内存占用非常大,线程的上下文切换带来的cpu开销很大,自然性能就上不去了,而这些开销完全是没有意义的。
为什么nginx可以采用异步非阻塞的方式来处理呢,或者异步非阻塞到底是怎么回事呢?我们先回到原点,看看一个请求的完整过程。首先,请求过来,要建立连接,然后再接收数据,接收数据后,再发送数据。具体到系统底层,就是读写事件,而当读写事件没有准备好时,必然不可操作,如果不用非阻塞的方式来调用,那就得阻塞调用了,事件没有准备好,那就只能等了,等事件准备好了,你再继续吧。阻塞调用会进入内核等待,cpu就会让出去给别人用了,对单线程的worker来说,显然不合适,当网络事件越多时,大家都在等待呢,cpu空闲下来没人用,cpu利用率自然上不去了,更别谈高并发了。好吧,你说加进程数,这跟apache的线程模型有什么区别,注意,别增加无谓的上下文切换。所以,在nginx里面,最忌讳阻塞的系统调用了。不要阻塞,那就非阻塞喽。非阻塞就是,事件没有准备好,马上返回EAGAIN,告诉你,事件还没准备好呢,你慌什么,过会再来吧。好吧,你过一会,再来检查一下事件,直到事件准备好了为止,在这期间,你就可以先去做其它事情,然后再来看看事件好了没。虽然不阻塞了,但你得不时地过来检查一下事件的状态,你可以做更多的事情了,但带来的开销也是不小的。所以,才会有了异步非阻塞的事件处理机制,具体到系统调用就是像select/poll/epoll/kqueue这样的系统调用。它们提供了一种机制,让你可以同时监控多个事件,调用他们是阻塞的,但可以设置超时时间,在超时时间之内,如果有事件准备好了,就返回。这种机制正好解决了我们上面的两个问题,拿epoll为例(在后面的例子中,我们多以epoll为例子,以代表这一类函数),当事件没准备好时,放到epoll里面,事件准备好了,我们就去读写,当读写返回EAGAIN时,我们将它再次加入到epoll里面。这样,只要有事件准备好了,我们就去处理它,只有当所有事件都没准备好时,才在epoll里面等着。这样,我们就可以并发处理大量的并发了,当然,这里的并发请求,是指未处理完的请求,线程只有一个,所以同时能处理的请求当然只有一个了,只是在请求间进行不断地切换而已,切换也是因为异步事件未准备好,而主动让出的。这里的切换是没有任何代价,你可以理解为循环处理多个准备好的事件,事实上就是这样的。与多线程相比,这种事件处理方式是有很大的优势的,不需要创建线程,每个请求占用的内存也很少,没有上下文切换,事件处理非常的轻量级。并发数再多也不会导致无谓的资源浪费(上下文切换)。更多的并发数,只是会占用更多的内存而已。 我之前有对连接数进行过测试,在24G内存的机器上,处理的并发请求数达到过200万。现在的网络服务器基本都采用这种方式,这也是nginx性能高效的主要原因。
我们之前说过,推荐设置worker的个数为cpu的核数,在这里就很容易理解了,更多的worker数,只会导致进程来竞争cpu资源了,从而带来不必要的上下文切换。而且,nginx为了更好的利用多核特性,提供了cpu亲缘性的绑定选项,我们可以将某一个进程绑定在某一个核上,这样就不会因为进程的切换带来cache的失效。像这种小的优化在nginx中非常常见,同时也说明了nginx作者的苦心孤诣。比如,nginx在做4个字节的字符串比较时,会将4个字符转换成一个int型,再作比较,以减少cpu的指令数等等。
4、Nginx事件处理模型
类似与Libevent,通过epoll,IO复用机制,做到大量的高并发服务请求。
5、Nginx信号处理
对nginx来说,有一些特定的信号,代表着特定的意义。信号会中断掉程序当前的运行,在改变状态后,继续执行。如果是系统调用,则可能会导致系统调用的失败,需要重入。对于nginx来说,如果nginx正在等待事件(epoll_wait
时),如果程序收到信号,在信号处理函数处理完后,epoll_wait
会返回错误,然后程序可再次进入epoll_wait
调用。判断epoll_wait
的返回可以处理很多事情,例如处理信号、处理超时、处理连接中断。
6、Nginx定时器处理
和Libevent的处理一模一样哦,只是Libevent将定时器事件放入了小根堆中。
epoll_wait
等函数在调用的时候是可以设置一个超时时间的,所以nginx借助这个超时时间来实现定时器。nginx里面的定时器事件是放在一颗维护定时器的红黑树里面,每次在进入epoll_wait
前,先从该红黑树里面拿到所有定时器事件的最小时间,在计算出epoll_wait
的超时时间后进入epoll_wait
。所以,当没有事件产生,也没有中断信号时,epoll_wait会超时,也就是说,定时器事件到了。这时,nginx会检查所有的超时事件,将他们的状态设置为超时,然后再去处理网络事件。由此可以看出,当我们写nginx代码时,在处理网络事件的回调函数时,通常做的第一个事情就是判断超时,然后再去处理网络事件。
一段伪代码来总结一下nginx的事件处理模型
while (true) {
for t in run_tasks:
t.handler();
update_time(&now);
timeout = ETERNITY;
for t in wait_tasks: /* sorted already */
if (t.time <= now) {
t.timeout_handler();
} else {
timeout = t.time - now;
break;
}
nevents = poll_function(events, timeout);
for i in nevents:
task t;
if (events[i].type == READ) {
t.handler = read_handler;
} else { /* events[i].type == WRITE */
t.handler = write_handler;
}
run_tasks_add(t);
}
3、Nginx配置通用语法
Nginx配置文件其实就是一个普通的文本文件。
下面是一个默认的配置文件,通过讲解这个,解释如何写配置文件。
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
server {
listen 8011;
server_name localhost;
charset utf-8;
location / {
alias /home/wangjun/Desktop/test_space/;
}
# server {
# listen 80;
# server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
# location / {
# root html;
# index index.html index.htm;
# }
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
# another virtual host using mix of IP-, name-, and port-based configuration
#
#server {
# listen 8000;
# listen somename:8080;
# server_name somename alias another.alias;
# location / {
# root html;
# index index.html index.htm;
# }
#}
# HTTPS server
#
#server {
# listen 443;
# server_name localhost;
# ssl on;
# ssl_certificate cert.pem;
# ssl_certificate_key cert.key;
# ssl_session_timeout 5m;
# ssl_protocols SSLv2 SSLv3 TLSv1;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
# location / {
# root html;
# index index.html index.htm;
# }
#}
}
1、块配置项
events
、http
、server
、location
等都是块配置项。块配置项一定会用大括号把一系列所属的配置项全包含进来,表示大括号内的配置项同时生效。所有的事件类配置都要在events
块中,http
、server
等配置也遵循这个规定。块配置项可以嵌套。 内层块直接继承外层块, 例如,上例中,server块里的任意配置都是基于http块里的已有配置的。当内外层块中的配置发生冲突时, 究竟是以内层块还是外层块的配置为准, 取决于解析这个配置项的模块。
server { #块配置名 大括号开始, 通过空格将二者分开,
listen 8011; #配置项值,通过空格分开,可以是多条取决于解析的模块是否支持。
server_name localhost; #每个配置的结尾通过;结束
charset utf-8;
location / {
alias /home/wangjun/Desktop/test_space/;
}
2、配置项单位
当指定空间大小,可以使用的单位包括如下:
- K或k字节(KB)
- M或m字节(MB)
- ms、s、m、h、d、w、M、y(毫秒 秒 分 小时 周 月 年)
单位是否生效,取决于配置项的解析模块。
在执行configure命令时, 我们已经把许多模块编译进Nginx中, 但是否启用这些模块, 一般取决于配置文件中相应的配置项。 换句话说, 每个Nginx模块都有自己感兴趣的配置项, 大部分模块都必须在nginx.conf中读取某个配置项后才会在运行时启用。 例如, 只有当配置http{…}这个配置项时, ngx_http_module模块才会在Nginx中启用, 其他依赖ngx_http_module的模块也才能正常使用。
4、Nginx服务基本配置
Nginx在运行时, 至少必须加载几个核心模块和一个事件类模块。 这些模块运行时所支持的配置项称为基本配置——所有其他模块执行时都依赖的配置项。由于配置项较多,所以把它们按照用户使用时的预期功能
分成了以下4类。
1、用于调试、 定位问题的配置项
1)是否通过守护进程方式运行Nginx:
守护进程(daemon)是脱离终端并且在后台运行的进程。 它脱离终端是为了避免进程执行过程中的信息在任何终端上显示, 这样一来, 进程也不会被任何终端所产生的信息所打断。Nginx毫无疑问是一个需要以守护进程方式运行的服务,因此,默认都是以这种方式运行。Nginx还是提供了关闭守护进程的模式,之所以提供这种模式,是为了方便跟踪调试Nginx,毕竟用gdb调试进程时最烦琐的就是如何继续跟进fork出的子进程了。
语法:daemon on/off;
默认:daemon on;
2)是否以master/worker方式工作
Nginx通常以是以一个master进程管理多个worker进程的方式运行,这样可以实现高并发以及控制分离。与daemon配置相同,提master_process
配置也是为了方便跟踪调试Nginx。 如果用关闭了master_process
方式, 就不会fork出worker子进程来处理请求, 而是用master进程自身来处理请求,类似与Libevent的处理方式,通过单进程处理高并发请求。
语法:master_process on/off;
默认:master_process on;
3)error日志设置
语法:error_log pathfile level;
默认:error_log logs/error.log;
可以自由设置error日志的路径和级别。pathfile
参数可以是一个具体的文件,默认是logs/error.log
,最好将它放到一个磁盘空间足够大的位置,pathfile
也可以是/dev/null
, 这样就不会输出任何日志了,这也是关闭error
日志的唯一手段。pathfile
也可以是stderr
, 这样日志会输出到标准错误文件中。
level是日志的输出级别,取值范围是debug、 info、 notice、 warn、error、crit、 alert、emerg
从左至右级别依次增大。当设定为一个级别时, 大于或等于该级别的日志都会被输出到pathfile
文件中, 小于该级别的日志则不会输出。 例如,当设定为error
级别时,error、
级别的日志都会输出。如果设定的日志级别是
crit、 alert、 emergdebug
, 则会输出所有的日志, 这样数据量会很大, 需要预先确保pathfile
所在磁盘有足够的磁盘空间。日志级别设定到debug
, 必须在configure
时加入--with-debug
配置项。
4)处理特殊调试点
语法: debug_points[stop|abort]
设定为stop
那么Nginx的代码执行到这些调试点时就会发出SIGSTOP
信号以用于调试。设定为abort
,则会产生一个coredump
文件, 可以使用gdb来查看Nginx当时的各种信息。通常不需要配置这项。
5)仅对指定的客户端输出debug级别的日志
语法: debug_connection[IP|CIDR]
这个配置项实际上属于事件类配置, 因此,它必须放在events{...}
中才有效。 它的值可以是IP地址或CIDR地址。
events {
debug_connection 10.224.66.14;
debug_connection 10.224.57.0/24;
}
这样, 仅仅来自以上IP地址的请求才会输出debug级别的日志,其他请求仍然沿用error_log
中配置的日志级别。上面这个配置对修复Bug很有用, 特别是定位高并发请求下才会发生的问题。
6)限制coredump核心转储文件的大小
语法: worker_rlimit_core size;
在Linux系统中,当进程发生错误或收到信号而终止时,系统会将进程执行时的内存内容(核心映像)写入一个文件(core文件),以作为调试之用,这就是所谓的核心转储(core dumps) 。当Nginx进程出现一些非法操作(如内存越界)导致进程直接被操作系统强制结束时,会生成核心转储core文件,可以从core文件获取当时的堆栈、 寄存器等信息,从而帮助我们定位问题。但这种core文件中的许多信息不一定是用户需要的,如果不加以限制,那么可能一个core文件会达到几GB,这样随便coredumps几次就会把磁盘占满,引发严重问题。 通过worker_rlimit_core
配置可以限制core文件的大小,从而有效帮助用户定位问题。
7)指定coredump
文件生成目录
语法: working_directory path;
worker进程的工作目录。这个配置项的唯一用途就是设置coredump
文件所放置的目录,协助定位问题。因此,需确保worker进程有权限向working_directory
指定的目录中写入文件。
以上7大调试策略,终究可以将Nginx的Bug定位出来。
2、正常运行的必备配置项
3、优化性能的配置项
4、事件类配置项
有些事件类配置项归纳到优化性能类,这是因为它们虽然也属于
events{}块, 但作用是优化性能。
1)是否打开accept锁
通过这个实现了负载均衡。
语法: accept_mutex[on|off]
默认: accept_mutext on;
accept_mutex
是Nginx的负载均衡锁。accept_mutex
这把锁可以让多个worker
进程轮流地、序列化地与新的客户端建立TCP连接。 当某一个worker进程建立的连接数量达到worker_connections
配置的最大连接数的7/8
时,会大大地减小该worker进程试图建立新TCP连接的机会, 以此实现所有worker进程之上处理的客户端请求数尽量接近。accept
锁默认是打开的, 如果关闭它,那么建立TCP连接的耗时会更短, 但是worker进程之间的负载会非常不均衡,因此不建议关闭它。
2)lock文件的路径
语法: lock_file path/file;
默认: lock_file logs/nginx.lock;
accept
锁可能需要这个lock
文件, 如果accept锁关闭, lock_file
配置完全不生效。如果打开了accept锁,并且由于编译程序、 操作系统架构等因素导致Nginx不支持原子锁, 这时才会用文件锁实现accept锁,这样lock_file
指定的lock文件才会生效。
3)使用accept锁后到真正建立连接之间的延迟时间
语法: accept_mutex_delay Nms;
默认: accept_mutex_delay 500ms;
在使用accept锁后,同一时间只有一个worker进程能够取到accept锁。 这个accept锁不是阻塞锁(Nginx拒绝阻塞调用),如果取不到会立刻返回。如果有一个worker进程试图取accept锁而没有取到, 它至少要等accept_mutex_delay
定义的时间间隔后才能再次试图取锁。
(4) 批量建立新连接
语法: multi_accept[on|off];
默认: multi_accept off;
当事件模型通知有新连接时, 尽可能地对本次调度中客户端发起的所有TCP请求都建立
连接。
5)选择事件模型
语法: use[kqueue|rtsig|epoll|/dev/poll|select|poll|eventport];
默认: Nginx会自动使用最适合的事件模型。
对于Linux操作系统来说, 可供选择的事件驱动模型有poll、 select、 epoll三种。 epoll当然是性能最高的一种。
6) 每个worker的最大连接数
语法: worker_connections number;
定义每个worker进程可以同时处理的最大连接数。
5、ngx_http_core_module
HTTP配置项自然必须全部在http{}
块之内,http{}
内可以包含server块
、 location块
、 upstream块或if块
等。Nginx为配置一个完整的静态Web服务器提供了非常多的功能,包括以下8类:虚拟主机与请求的分发、文件路径的定义、内存及磁盘资源的分配、网络连接的设置、MIME类型的设置、对客户端请求的限制、文件操作的优化、对客户端请求的特殊处理。
1、虚拟主机与请求的分发
基于域名的虚拟主机是最常见的一种虚拟主机。只需配置你的DNS服务器,将每个主机名映射到正确的lP地址,然后配置Nginx服务器,令其识别不同的主机名就可以了。这种虚拟主机技术,使很多虚拟主机可以共享同一个lP地址,有效解决了lP地址不足的问题。所以,如果没有特殊要求使你必须用一个基于lP的虚拟主机,最好还是使用基于域名的虚拟主机。
1)监听端口,最好去看官方文档
Syntax: listen address[:port] [default_server] [ssl] [http2 | spdy] [proxy_protocol] [setfib=number] [fastopen=number] [backlog=number] [rcvbuf=size] [sndbuf=size] [accept_filter=filter] [deferred] [bind] [ipv6only=on|off] [reuseport] [so_keepalive=on|off|[keepidle]:[keepintvl]:[keepcnt]];
listen port [default_server] [ssl] [http2 | spdy] [proxy_protocol] [setfib=number] [fastopen=number] [backlog=number] [rcvbuf=size] [sndbuf=size] [accept_filter=filter] [deferred] [bind] [ipv6only=on|off] [reuseport] [so_keepalive=on|off|[keepidle]:[keepintvl]:[keepcnt]];
listen unix:path [default_server] [ssl] [http2 | spdy] [proxy_protocol] [backlog=number] [rcvbuf=size] [sndbuf=size] [accept_filter=filter] [deferred] [bind] [so_keepalive=on|off|[keepidle]:[keepintvl]:[keepcnt]];
Default:
listen *:80 | *:8000;
Context: server
listen参数决定Nginx服务如何监听端口,在listen
后可以只加IP地址、端口或主机名。
listen 127.0.0.1:8000;
listen 127.0.0.1;#默认采用80端口
listen 8000;
listen *:8000;
listen localhost:8000;
2)主机名称
Syntax: server_name name ...;
Default:
server_name "";
Context: server
server {
server_name example.com www.example.com;
}
例如在上述虚拟主机配置多个主机名,当对应的主机域名到来时候,通过这个虚拟主机处理。在开始处理一个HTTP请求时, Nginx会取出header头中的Host, 与每个server中的server_name进行匹配, 以此决定到底由哪一个server块来处理这个请求。 有可能一个Host与多个server块中的server_name都匹配, 这时就会根据匹配优先级来选择实际处理的server块。
4)根据HTTP返回码重定向页面
语法: error_page code[code...][=|=answer-code]uri|@named_location
重定向:
当对于客户端某个请求返回错误码时,如果匹配上了error_page中设置code,则服务器端回应302临时重定向响应消息,其中重定向URL为error_page
里面设定的location
。
例如有如下设置:
error_page 404 404.html;
error_page 502 503 504 50x.html;
error_page 403 http://example.com/forbidden.html
error_page 404 = @fetch;
虽然重定向了URI,但返回的HTTP错误码还是与原来的相同。用户可以通过“=”来更改返回的错误码。
error_page 404 =200 empty.gif;
error_page 404 =403 forbidden.gif;
也可以不指定确切的返回错误码,而是由重定向后实际处理的真实结果来决定,这时,只要把“=”后面的错误码去掉即可。
error_page 404 = /empty.gif;
如果不想修改URI,只是想让这样的请求重定向到另一个location中进行处理,那么可以这样设置。
location / (
error_page 404 @fallback;
)
location @fallback (
proxy_pass http://backend;
)
这样, 返回404的请求会被反向代理到http://backend
上游服务器中处理。
5)是否允许递归使用error_page
语法: recursive_error_pages[on|off];
默认: recursive_error_pages off;
确定是否允许递归地定义error_page
6)try_files
语法: try_files path1[path2] uri;
try_files
后要跟若干路径,如path1 path2等
而且最后必须要有URI参数,意义如下:请求到来服务端尝试按照顺序访问每一个path
,如果可以有效地读取,就直接向用户返回这个path对应的文件结束请求, 否则继续向下访问。如果所有的path
都找不到有效的文件,就重定向到最后的参数URI
上。因此,最后这个参数URI
必须存在,而且它应该是一个可以有效重定向的URI
。
例如:
try_files system/maintenance.html $uri $uri/index.html $uri.html @other;
location @other {
proxy_pass http://backend;
}
#如果前面的路径,如system/maintenance.html等,都找不到,就会反向代理到http://backend服务上。
location {
try_files $uri $uri /error.phpc=404 =404;
}
2、文件路径的定义
3、内存及磁盘资源的分配
4、网络连接的设置
5、MIME类型的设置
6、对客户端请求的限制
7、文件操作的优化
8、对客户端请求的特殊处理
5、Nginx 方向代理模块配置项
参考:
Nginx开发从入门到精通
深入理解Nginx
http://nginx.org/en/docs/