原文链接:https://www.zybuluo.com/phper/note/89391
nginx在前面,我写过好几篇,相似的介绍它在各个平台上的安装配置以及和php-fpm的连接等。今天,这一篇,着重讲解它的配置,其中包括它比较擅长的负载均衡和反向代理,还有虚拟主机功能。
nginx启动和关闭
按照惯例,先说下各个平台的配置情况:
centos平台,源码安装的:
1 | /usr/local/nginx/nginx # 启动 |
mac平台,我用brew安装的。
1 | /usr/local/bin/nginx # 启动 |
nginx.conf配置文件详解
其实,对比,apache的配置文件,它的相对比较清晰和简单,之前觉得很难,现在沉下心来想想,其实很简单。大致的分块下,基本就分为以下几块:
1 | main |
nginx配置文件主要分为六个区域:main(全局设置)
、events(nginx工作模式)
、http(http设置)
、sever(主机设置)
、location(URL匹配)
、upstream(负载均衡服务器设置)
。
main模块
下面时一个main区域,他是一个全局的设置:
1 | user nobody nobody; |
user
来指定Nginx Worker进程运行用户以及用户组,默认由nobody账号运行。
worker_processes
来指定了Nginx要开启的子进程数。每个Nginx进程平均耗费10M~12M内存。根据经验,一般指定1个进程就足够了,如果是多核CPU,建议指定和CPU的数量一样的进程数即可。我这里写2,那么就会开启2个子进程,总共3个进程。
error_log
用来定义全局错误日志文件。日志输出级别有debug、info、notice、warn、error、crit可供选择,其中,debug输出日志最为最详细,而crit输出日志最少。
pid
用来指定进程id的存储文件位置。
worker_rlimit_nofile
用于指定一个nginx进程可以打开的最多文件描述符数目,这里是65535,需要使用命令“ulimit -n 65535”来设置。
events 模块
events模块来用指定nginx的工作模式和工作模式及连接数上限,一般是这样:
1 | events { |
use
用来指定Nginx的工作模式。Nginx支持的工作模式有select、poll、kqueue、epoll、rtsig和/dev/poll。其中select和poll都是标准的工作模式,kqueue和epoll是高效的工作模式,不同的是epoll用在Linux平台上,而kqueue用在BSD系统中,因为Mac基于BSD,所以Mac也得用这个模式,对于Linux系统,epoll工作模式是首选。
worker_connections
用于定义Nginx每个进程的最大连接数,即接收前端的最大请求数,默认是1024。最大客户端连接数由worker_processes
和worker_connections
决定,即Max_clients=worker_processes*worker_connections
,在作为反向代理时,Max_clients变为:Max_clients = worker_processes * worker_connections/4
。
进程的最大连接数受Linux系统进程的最大打开文件数限制,在执行操作系统命令“ulimit -n 65536”后worker_connections的设置才能生效。
http 模块
http模块可以说是最核心的模块了,它负责HTTP服务器相关属性的配置,它里面的server和upstream子模块,至关重要,等到反向代理和负载均衡以及虚拟目录等会仔细说。
1 | http{ |
下面详细介绍下这段代码中每个配置选项的含义。include
用来设定文件的mime类型,类型在配置文件目录下的mime.type文件定义,来告诉nginx来识别文件类型。
default_type
设定了默认的类型为二进制流,也就是当文件类型未定义时使用这种方式,例如在没有配置asp 的locate 环境时,Nginx是不予解析的,此时,用浏览器访问asp文件就会出现下载了。
log_format
用于设置日志的格式,和记录哪些参数,这里设置为main
,刚好用于access_log
来记录这种类型。
main的类型日志如下:也可以增删部分参数。
1 | 127.0.0.1 - - [21/Apr/2015:18:09:54 +0800] "GET /index.php HTTP/1.1" 200 87151 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.76 Safari/537.36" |
access_log
用来纪录每次的访问日志的文件地址,后面的main
是日志的格式样式,对应于log_format
的main
。
sendfile
参数用于开启高效文件传输模式。将tcp_nopush和tcp_nodelay两个指令设置为on用于防止网络阻塞。
keepalive_timeout
设置客户端连接保持活动的超时时间。在超过这个时间之后,服务器会关闭该连接。
还有很多各种配置,以后等用到来再说。
server 模块
sever 模块是http的子模块,它用来定一个虚拟主机,我们先讲最基本的配置,这些在后面再讲。
我们看一下一个简单的server 是如何做的?
1 | server { |
server
标志定义虚拟主机开始。listen
用于指定虚拟主机的服务端口。server_name
用来指定IP地址或者域名,多个域名之间用空格分开。root
表示在这整个server
虚拟主机内,全部的root web根目录。注意要和locate {}
下面定义的区分开来。index
全局定义访问的默认首页地址。注意要和locate {}
下面定义的区分开来。charset
用于设置网页的默认编码格式。access_log
用来指定此虚拟主机的访问日志存放路径,最后的main用于指定访问日志的输出格式。
location 模块
location模块是nginx中用的最多的,也是最重要的模块了,什么负载均衡啊、反向代理啊、虚拟域名啊都与它相关。慢慢来讲:
location 根据它字面意思就知道是来定位的,定位URL,解析URL,所以,它也提供了强大的正则匹配功能,也支持条件判断匹配,用户可以通过location指令实现Nginx对动、静态网页进行过滤处理。像我们的php环境搭建就是用到了它。
我们先来看这个,设定默认首页和虚拟机目录。
1 | location / { |
location /
表示匹配访问根目录。
root
指令用于指定访问根目录时,虚拟主机的web目录,这个目录可以是相对路径(相对路径是相对于nginx的安装目录)。也可以是绝对路径。
index
用于设定我们只输入域名后
访问的默认首页地址,有个先后顺序:index.php index.html index.htm
,如果没有开启目录浏览权限,又找不到这些默认首页,就会报403错误。
location 还有一种方式就是正则匹配,开启正则匹配这样:location ~
。后面加个~
。
下面这个例子是运用正则匹配
来链接php。我们之前搭建环境也是这样做:
1 | location ~ \.php$ { |
\.php$
熟悉正则的我们直到,这是匹配.php
结尾的URL,用来解析php文件。里面的root
也是一样,用来表示虚拟主机的根目录。fast_pass
链接的是php-fpm
的地址,之前我们也搭建过。其他几个参数我们以后再说。
location 还有其他用法,等讲到实例的时候,再看吧。
upstream 模块
upstream 模块负债负载均衡模块,通过一个简单的调度算法来实现客户端IP到后端服务器的负载均衡。我先学习怎么用,具体的使用实例以后再说。
1 | upstream iyangyi.com{ |
在上面的例子中,通过upstream
指令指定了一个负载均衡器的名称iyangyi.com
。这个名称可以任意指定,在后面需要的地方直接调用即可。
里面是ip_hash
这是其中的一种负载均衡调度算法,下面会着重介绍。紧接着就是各种服务器了。用server
关键字表识,后面接ip。
Nginx的负载均衡
模块目前支持4种调度算法
:
- weight 轮询(默认)。每个请求按时间顺序逐一分配到不同的后端服务器,如果后端某台服务器宕机,故障系统被自动剔除,使用户访问不受影响。weight。指定轮询权值,weight值越大,分配到的访问机率越高,主要用于后端每个服务器性能不均的情况下。
- ip_hash。每个请求按访问IP的hash结果分配,这样来自同一个IP的访客固定访问一个后端服务器,有效解决了动态网页存在的session共享问题。
- fair。比上面两个更加智能的负载均衡算法。此种算法可以依据页面大小和加载时间长短智能地进行负载均衡,也就是根据后端服务器的响应时间来分配请求,响应时间短的优先分配。Nginx本身是不支持fair的,如果需要使用这种调度算法,必须下载Nginx的upstream_fair模块。
- url_hash。按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,可以进一步提高后端缓存服务器的效率。Nginx本身是不支持url_hash的,如果需要使用这种调度算法,必须安装Nginx 的hash软件包。
在HTTP Upstream模块中,可以通过server指令指定后端服务器的IP地址和端口,同时还可以设定每个后端服务器在负载均衡调度中的状态。常用的状态有:
- down,表示当前的server暂时不参与负载均衡。
- backup,预留的备份机器。当其他所有的非backup机器出现故障或者忙的时候,才会请求backup机器,因此这台机器的压力最轻。
- max_fails,允许请求失败的次数,默认为1。当超过最大次数时,返回proxy_next_upstream 模块定义的错误。
- fail_timeout,在经历了max_fails次失败后,暂停服务的时间。max_fails可以和fail_timeout一起使用。
注意 当负载调度算法为ip_hash时,后端服务器在负载均衡调度中的状态不能是weight和backup。
参考文件:
http://blog.csdn.net/xifeijian/article/details/20956605
http://www.360doc.com/content/13/1114/12/7694408_329125489.shtml
http://www.cnblogs.com/xiaogangqq123/archive/2011/03/02/1969006.html
http://ixdba.blog.51cto.com/2895551/790611
http://freeloda.blog.51cto.com/2033581/1288553
下面看下虚拟主机、负债均衡和反向代理,是如何做到的。
1. 基于域名的虚拟主机
在apache上搭建基于域名的虚拟主机很简单,我之前也写过一篇,来讲述如何搭建。在nginx上搭建也不难。
假设我们在本地开发有3个项目,分别在hosts里映射到本地的127.0.0.1上:
1 | 127.0.0.1 www.iyangyi.com iyangyi.com |
有这样3个项目,分别对应于web根目录下的3个文件夹,我们用域名对应文件夹名字,这样子好记:
1 | /Users/yangyi/www/www.iyangyi.com/ |
每个目录下都有一个index.php文件,都素简单的输入自己的域名。
下面我们就来搭建这3个域名的虚拟主机,很显然,我们要新建3个server
来完成。为了看起来简洁好看,我们使用require
来包含外面的3个server
在nginx.conf
中,这样就清晰了很多。不会使得这个nginx.conf
内容太多:
1 | main |
既然每一个conf
都是一个server
,前面已经学习了一个完整的server
写的了。下面就开始:
1 | # www.iyangyi.conf |
1 | # api.iyangyi.conf |
1 | # admin.iyangyi.conf |
这样3个很精简的虚拟域名就搭建好了。重启下nginx,然后打开浏览器访问一下这3个域名,就能看到对应的域名内容了。
2.反向代理
正向代理
在说啥啥反向代理之前,先说下什么是代理
或者正向代理
。
正向代理
也就是代理,他的工作原理就像一个跳板,简单的说,我访问不了google.com,但是我能访问一个代理服务器A,A能访问google.com,于是我先连上代理服务器A,告诉他我需要google.com的内容,A就去取回来,然后返回给我。从网站的角度,只在代理服务器来取内容的时候有一次记录,有时候并不知道是用户的请求,也隐藏了用户的资料,这取决于代理告不告诉网站。
结论就是,正向代理
是一个位于客户端
和原始服务器(origin server)
之间的服务器。为了从原始服务器取得内容,客户端向代理发送一个请求并指定目标(原始服务器),然后代理向原始服务器转交请求并将获得的内容返回给客户端。
目前代理软件很多,浏览器上的代理就更多了。什么自由门啊,红杏等。
反向代理
ok,说完正向代理,再来说啥是反向代理
!
举个例子,比如我想访问 http://www.test.com/readme
,但www.test.com
上并不存在readme
页面,于是他是偷偷从另外一台服务器上取回来,然后作为自己的内容返回用户,但用户并不知情。这里所提到的 www.test.com 这个域名对应的服务器就设置了反向代理功能
。
结论就是,反向代理
正好相反,对于客户端而言它就像是原始服务器,并且客户端不需要进行任何特别的设置。客户端向反向代理的命名空间(name-space)中的内容发送普通请求,接着反向代理将判断向何处(原始服务器)转交请求,并将获得的内容返回给客户端,就像这些内容原本就是它自己的一样。
嗯。正向代理和反向代理就基本清楚了,那我们就来用nginx来配置一个反向代理。
nginx 使用反向代理,主要是使用location
模块下的proxy_pass
选项。
我们直接实战吧!
来个最简单的。当我访问 mac 上的nginx 的 centos.iyangyi.com 的内容时候, 就反向代理到虚拟机centos上的 apache 192.168.33.10 的index.html页面。
192.168.33.10 中的html 是很简单的一句输出:
1 | centos apache2 index.html |
在hosts里新加上这个域名。
1 | #vi /etc/hosts |
在vhost目录中新建一个conf server
1 | #centos.iyangyi.conf |
重启下nginx:
1 | sudo nginx -s reload |
打开浏览器,就可以看到页面输出了:
1 | centos apache2 index.html |
当然。proxy 还有其他的参数,比如:proxy_set_header
用来设置header头部信息参数转发等,等用了可以仔细看看。
3.负载均衡
别被这个名字给吓住了,以为是什么很牛逼的东西的。其实不然。也很简单。
先简单说下负载均衡是干嘛的?举个例子:我们的小网站,刚开始就一台nginx服务器,后来,随着业务量增大,用户增多,一台服务器已经不够用了,我们就又多加了几台服务器。那么这几台服务器如何调度?如何均匀的提供访问?这就是负载均衡。
负载均衡的好处是可以集群多台机器一起工作,并且对外的IP 和 域名是一样的,外界看起来就好像一台机器一样。
nginx 也刚好提供了强大而又简单的负载均衡功能。
在第一节中,我详细讲了nginx的负载均衡模块upstream
,负载均衡呢,主要是用这个模块。
我们先用vagrant搭建一个centos虚拟机集群(附vagrantfile文件)
1 | Vagrant.configure(2) do |config| |
分别配置静态ip并且取名字:
1 | web1 192.168.33.11 |
然后,我们分别启动vagrant ssh web1,web2,web3
,并且分别用yum
简单安装好apache
。并在www
目录里面新建index.html
,分别输出一句简单的web1
、web2
、web3
。
好,这个时候,我们在浏览器里输入对应的IP就会显示对应的web*
名字了。
ok,我们再来配置mac下的nginx,前面说过,主要是用nginx的upstream
,我接下来要完成的需求就是当我访问upstram.iyangyi.com
时,会自动的负载均衡到这3个服务器上去。
先在hosts里加上
1 | 127.0.0.1 upstream.iyangyi.com |
好,按照惯例,新建一个upstream.iyangyi.conf
的server配置文件。
基于 weight 权重的负载
先来一个最简单的,weight权重的:
1 | upstream webservers{ |
重启nginx nginx -s reload
,打开浏览器输入upstream.iyangyi.com
,不断刷新下,就能看到变化显示web1,web2,web3
。说明我们的负载均衡起作用了。
我们再打开web[1-3]的apache的访问日志:
1 | sudo vi /var/log/httpd/access_log |
上面也显示出了ip为这台mac的地址。说明负载均衡已经生效。
我们再来继续看几个参数 : max_fails
和fail_timeout
max_fails : 允许请求失败的次数,默认为1。当超过最大次数时,返回proxy_next_upstream 模块定义的错误。
fail_timeout : 在经历了max_fails次失败后,暂停服务的时间。max_fails可以和fail_timeout一起使用,进行健康状态检查。
1 | server 192.168.33.11 weight=1 max_fails=2 fail_timeout=30s; |
所以这2个一起搭配使用,表示:当失败2次的时候,就停止使30秒
好,我们来继续做实验,将web1
的httpd服务停掉,然后我们加上max_fails可以和fail_timeout。
1 | sudo /usr/sbin/apachectl stop |
1 | upstream webservers{ server 192.168.33.11 weight=10 max_fails=2 fail_timeout=30s; server 192.168.33.12 weight=10 max_fails=2 fail_timeout=30s; server 192.168.33.13 weight=10 max_fails=2 fail_timeout=30s;} |
重启nginx,然后刷新upstream.iyangyi.com
,就能看到变化显示,只有web2,web3
,web1
没有了。
看下日志,显示web1 挂了:
1 | 2015/05/14 15:15:56 [error] 2381#0: *93 kevent() reported that connect() failed (61: Connection refused) while connecting to upstream, client: 127.0.0.1, server: upstream.iyangyi.com, request: "GET / HTTP/1.1", upstream: "http://192.168.33.11:80/", host: "upstream.iyangyi.com" |
我们再来继续看剩下几个参数 : down
和backup
down 表示这台机器暂时不参与负载均衡。相当于注释掉了。
backup 表示这台机器是备用机器,是其他的机器不能用的时候,这台机器才会被使用,俗称备胎
O__O “…
我们继续来做实验,改一下,先把web1
改成down
,然后将web3改成backup
:
1 | upstream webservers{ |
重启下nginx,然后刷新下,不管怎么刷新,都显示是web2
。
接下来,我们将web2 的服务停掉:
1 | sudo /usr/sbin/apachectl stop |
然后,我们再刷新下网页,看下备胎web3是不是被启用了:果然,页面上输出了web3
。
基于 ip_hash 的负载
这种分配方式,每个请求按访问IP的hash结果分配,这样来自同一个IP的访客固定访问一个后端服务器,有效解决了动态网页存在的session共享问题。
动手看怎么操作:
1 | upstream webservers{ ip_hash; server 192.168.33.11 weight=1 max_fails=2 fail_timeout=30s; server 192.168.33.12 weight=1 max_fails=2 fail_timeout=30s; server 192.168.33.13 down;} |
重启nginx,我们刷新,发现,再怎么刷,都是web1
, 是固定的了。
我们讲web2的权重该大一点:
1 | upstream webservers{ ip_hash; server 192.168.33.11 weight=1 max_fails=2 fail_timeout=30s; server 192.168.33.12 weight=2 max_fails=2 fail_timeout=30s; server 192.168.33.13 down;} |
这样就会永远是web2了。
我们试着把web2服务关掉,再刷新,就会输出web1
了,已经切换过来了。
注意
ip_hash 模式下,最好不要设置weight
参数,因为你设置了,就相当于手动设置了,将会导致很多的流量分配不均匀。
ip_hash模式下, backup
参数不可用,加了会报错,为啥呢?因为,本身我们的访问就是固定的了,其实,备用已经不管什么作用了。
4.页面缓存
页面缓存也是日常web 开发中很重要的一个环节,对于一些页面,我们可以将其静态化,保存起来,下次请求时候,直接走缓存,而不用去请求反相代理服务器甚至数据库服务了。从而减轻服务器压力。
nginx 也提供了简单而强大的下重定向
,反向代理
的缓存功能,只需要简单配置下,就能将指定的一个页面缓存起来。它的原理也很简单,就是匹配当前访问的url, hash加密后,去指定的缓存目录找,看有没有,有的话就说明匹配到缓存了。
好。现在开始学习!
我们先来看一下一个简单的页面缓存的配置:
1 | http { |
下面我们来一步一步说。用到的配置参数,主要是proxy_*
前缀的很多配置。
首先需要在http
中加入proxy_cache_path
它用来制定缓存的目录以及缓存目录深度制定等。它的格式如下:
1 | proxy_cache_path path [levels=number] keys_zone=zone_name:zone_size [inactive=time] [max_size=size]; |
1. path
是用来指定 缓存在磁盘的路径地址。比如:/data/nginx/cache
。那以后生存的缓存文件就会存在这个目录下。
2. levels
用来指定缓存文件夹的级数,可以是:levels=1
, levels=1:1
, levels=1:2
, levels=1:2:3
可以使用任意的1位或2位数字作为目录结构分割符,如 X
, X:X
,或 X:X:X
例如: 2
, 2:2
, 1:1:2
,但是最多只能是三级目录。
那这个里面的数字是什么意思呢。表示取hash值的个数。比如:现在根据请求地址localhost/index.php?a=4 用md5进行哈希,得到e0bd86606797639426a92306b1b98ad9
1 | levels=1:2` 表示建立2级目录,把hash最后1位(9)拿出建一个目录,然后再把9前面的2位(ad)拿来建一个目录, 那么缓存文件的路径就是`/data/nginx/cache/9/d/e0bd86606797639426a92306b1b98ad9 |
以此类推:levels=1:1:2
表示建立3级目录,把hash最后1位(9)拿出建一个目录,然后再把9前面的1位(d)建一个目录, 最后把d前面的2位(8a)拿出来建一个目录 那么缓存文件的路径就是/data/nginx/cache/9/d/8a/e0bd86606797639426a92306b1b98ad9
3. keys_zone
所有活动的key和元数据存储在共享的内存池中,这个区域用keys_zone参数指定。one指的是共享池的名称,10m指的是共享池的大小。
注意每一个定义的内存池必须是不重复的路径,例如:
1 | proxy_cache_path /data/nginx/cache/one levels=1 keys_zone=one:10m;proxy_cache_path /data/nginx/cache/two levels=2:2 keys_zone=two:100m;proxy_cache_path /data/nginx/cache/three levels=1:1:2 keys_zone=three:1000m; |
4. inactive
表示指定的时间内缓存的数据没有被请求则被删除,默认inactive为10分钟。inactive=1d
1小时。inactive=30m
30分钟。
5. max_size
表示单个文件最大不超过的大小。它被用来删除不活动的缓存和控制缓存大小,当目前缓存的值超出max_size指定的值之后,超过其大小后最少使用数据(LRU替换算法)将被删除。max_size=10g
表示当缓存池超过10g就会清除不常用的缓存文件。
6. clean_time
表示每间隔自动清除的时间。clean_time=1m
1分钟清除一次缓存
好。说完了这个很重要的参数。我们再来说在server
模块里的几个配置参数:
1 | proxy_cache` 用来指定用哪个`keys_zone`的名字,也就是用哪个目录下的缓存。上面我们指定了三个`one, two,three` 。比如,我现在想用`one` 这个缓存目录 : `proxy_cache one |
proxy_cache_key
这个其实蛮重要的,它用来指定生成hash的url地址的格式。他会根据这个key映射成一个hash值,然后存入到本地文件。proxy_cache_key $host$uri
表示无论后面跟的什么参数,都会访问一个文件,不会再生成新的文件。
而如果proxy_cache_key $is_args$args
,那么传入的参数 localhost/index.php?a=4 与localhost/index.php?a=44将映射成两个不同hash值的文件。
proxy_cache_key
默认是 "$scheme$host$request_uri"
。但是一般我们会把它设置成:$host$uri$is_args$args
一个完整的url路径。
proxy_cache_valid
它是用来为不同的http响应状态码设置不同的缓存时间,
1 | proxy_cache_valid 200 302 10m;proxy_cache_valid 404 1m; |
表示为http status code 为200和302的设置缓存时间为10分钟,404代码缓存1分钟。
如果只定义时间:
1 | proxy_cache_valid 5m; |
那么只对代码为200, 301和302的code进行缓存。
同样可以使用any参数任何相响应:
1 | proxy_cache_valid 200 302 10m;proxy_cache_valid 301 1h;proxy_cache_valid any 1m; #所有的状态都缓存1小时 |
好。缓存的基本一些配置讲完了。也大致知道了怎么使用这些参数。
现在开始实战!我们启动一台vagrant linux 机器 web1 (192.168.33.11) 用作远程代理机器,就不搞复杂的负载均衡了。
先在Mac本地加一个域名cache.iyangyi.com
, 然后按照上面的配置在vhost 下新建一个proxy_cache.iyangyi.conf
文件:
1 | proxy_cache_path /usr/local/var/cache levels=1:2 keys_zone=cache_zone:10m inactive=1d max_size=100m; |
当然缓存文件夹 /usr/local/var/cache
得提前新建好。然后重启nginx。
192.168.33.11 是apache服务器,在index.html页面就写了一个web1
。
我们打开浏览器访问 cache.iyangyi.com
。就能看到web1
了。
打开审核元素
或者firebug
。看network网络请求
选项,我们可以看到,Response Headers,在这里我们可以看到:
1 | X-Cache:MISS |
X-cache 为 MISS
表示未命中,请求被传送到后端。y因为是第一次访问,没有缓存,所以肯定是未命中。我们再刷新下,就发现其变成了HIT
, 表示命中。它还有其他几种状态:
MISS 未命中,请求被传送到后端
HIT 缓存命中
EXPIRED 缓存已经过期请求被传送到后端
UPDATING 正在更新缓存,将使用旧的应答
STALE 后端将得到过期的应答
BYPASS 缓存被绕过了
我们再去看看缓存文件夹 /usr/local/var/cache
里面是否有了文件:
1 | cache git:(master) cd a/13 |
已经生成了缓存文件。
我们在url 后面随便加一个什么参数,看会不会新生成一个缓存文件夹及文件: http://cache.iyangyi.com/?w=ww55
。因为我们使用的生成规则是全部url转换(proxy_cache_key $host$uri$is_args$args
;)
查看 X-cache 为 MISS
,再刷新 ,变成HIT
。再去看一下缓存文件夹 /usr/local/var/cache
。
1 | ~cache git:(master) ls |
果然又生成了一个4文件夹。
参考资料:http://freeloda.blog.51cto.com/2033581/1288553
前面几节,陆陆续续的说了nginx平时做的大部分工作。第3篇主要讲还是蛮重要的URL路由重写
和读写分离
。
nginx中的 location 正则模块
用过apache的知道,apache也是可以配置URL重写的,我之前一篇中也详细的写过:apache的虚拟域名rewrite配置以及.htaccess的使用。
这一小节,主要来学习nginx中的URL重写怎么做。url重写模块,主要是在location
模块面来实现,我们一点一点的看。
首先看下location 正则匹配
的使用。
还记得之前是如何用location
来定位.php
文件的吗?
1 | location ~ \.php$ { |
我们用~
来表示location开启正则匹配, 这样:location ~
。
还可以用这个来匹配静态资源,缓存它们,设置过期时间:
1 | location ~ .*\.(gif|jpg|jpeg|bmp|png|ico|txt|mp3|mp4|swf){ |
expires
用来设置HTTP应答中的Expires
和Cache-Control
的头标时间,来告诉浏览器访问这个静态文件时,不用再去请求服务器,直接从本地缓存读取就可以了。
1 | 语法: expires [time|epoch|max|off] |
可以在time值中使用正数或负数。“Expires”头标的值将通过当前系统时间加上您设定的 time 值来获得。
可以设置的参数如下:
epoch
指定“Expires”的值为 1 January, 1970, 00:00:01 GMT。max
指定“Expires”的值为 31 December 2037 23:59:59 GMT,“Cache-Control”的值为10年。-1
指定“Expires”的值为 服务器当前时间 -1s,即永远过期负数
:Cache-Control: no-cache正数或零
:Cache-Control: max-age = #, # 会转换为指定时间的秒数。比如:1d
、2h
、3m
。off
表示不修改“Expires”和“Cache-Control”的值
比如再看个例子:
控制图片等过期时间为30天
1 | location~ \.(gif|jpg|jpeg|png|bmp|ico)$ { |
我们还可以控制哪一个文件目录的时间,比如控制匹配/resource/或者/mediatorModule/里所有的文件缓存设置到最长时间。
1 | location ~ /(resource|mediatorModule)/ { |
实战一下。我们设置下过期时间,然后用chrome看下http头部情况。
我把这张图片的expires
设置为30天,我们看图中的cache-control
和Expires
看到了,有30天的缓存了。说明生效了。我们再看下nginx的访问日志:
看下code码,都是304,表示未修改,告诉浏览器直接读本地的。也就是说缓存生效了。
URL重写模块(Rewrite)
重写模块与很多模块一起使用。先看一下是怎么用的,看2个例子,然后我们再一点一点讲每个的使用方法:
1 | location /download/ { |
1 | location / { |
上面2个例子就是利用rewrite
来完成URL重写的。我们慢慢来看它的用法。
break
break 和变成语言中的用法一样,就是跳出某个逻辑。
语法:break
默认值:none
使用字段:server, location, if
1 | if (!-f $request_filename) { break;} |
上面这个例子就是在if
里面使用break
,意思是如果访问的文件名不存在,就跳出。后续会有更多的例子。
if
语法:if (condition) { … }
默认值:none
使用字段:server, location
if 判断一个条件,如果条件成立,则后面的大括号内的语句将执行,相关配置从上级继承。
可以在判断语句中指定下列值:
- 一个变量的名称;不成立的值为:空字符传”“或者一些用“0”开始的字符串。
- 一个使用=或者!=运算符的比较语句。
- 使用符号
*和模式匹配的正则表达式:- ~为区分大小写的匹配。
- ~*不区分大小写的匹配(firefox匹配FireFox)。
- !
和!*意为“不匹配的”。- 使用-f和!-f检查一个文件是否存在。
- 使用-d和!-d检查一个目录是否存在。
- 使用-e和!-e检查一个文件,目录或者软链接是否存在。
- 使用-x和!-x检查一个文件是否为可执行文件。
我们一一来举例看看。
1 | if ($http_user_agent ~ MSIE) { rewrite ^(.*)$ /msie/$1 break;} |
$http_user_agent
变量获取浏览器的agent,使用~
来匹配大小写
用户如果使用的IE 浏览器,就执行if 里面的操作。
1 | if ($request_method = POST ) { return 405;} |
$request_method
变量获取请求的方法,使用=
来判断是否等于POST 。如果复合,就执行if 里面的操作。
1 | if (!-f $request_filename) { break; proxy_pass http://127.0.0.1;} |
$request_filename
变量获取请求的文件名,使用!-f
来匹配文件,如果不是一个文件名,就执行if 里面的逻辑。
return
语法:return code
默认值:none
使用字段:server, location, if
这个指令结束执行配置语句并为客户端返回状态代码,可以使用下列的值:204,400,402-406,408,410, 411, 413, 416与500-504。此外,非标准代码444将关闭连接并且不发送任何的头部。
rewrite
语法:rewrite regex replacement flag
默认值:none
使用字段:server, location, if
rewrite用来重写url,有3个位置:
regex 表示用来匹配的正则
replacement 表示用来替换的
flag 是尾部的标记:
flag可以是以下的值:
- last - url重写后,马上发起一个新的请求,再次进入server块,重试location匹配,超过10次匹配不到报500错误,地址栏url不变
- break - url重写后,直接使用当前资源,不再执行location里余下的语句,完成本次请求,地址栏url不变
- redirect - 返回302临时重定向,url会跳转,爬虫不会更新url。
- permanent - 返回301永久重定向。url会跳转。爬虫会更新url。
- 为空 - URL 不会变,但是内容已经变化,也是永久性的重定向
上面的正则表达式的一部分可以用圆括号,方便之后按照顺序用$1-$9来引用。
我们来看几个例子:
我们需要将/photos/123456重写成/path/to/photos/12/1234/123456.png
可以这样:
1 | rewrite "/photos/([0-9] {2})([0-9] {2})([0-9] {2})" /path/to/photos/$1/$1$2/$1$2$3.png; |
下面是一些简单的常见的重写。
1 | rewrite ^/js/base.core.v3.js /js/base.core.v3.dev.js redirect; |
- 本文链接:https://zeozzz.github.com/2019/04/29/30/
- 版权声明:本博客所有文章除特别声明外,均默认采用 许可协议。