Nginx基础


一、简介

Nginx(“engine x”)一个具有高性能的【HTTP】和【反向代理】的【WEB服务器】,同时也是一个【POP3/SMTP/IMAP代理服务器】。

Nginx的优点

(1)速度更快、并发更高

单次请求或者高并发请求的环境下,Nginx都会比其他Web服务器响应的速度更快。一方面在正常情况下,单次请求会得到更快的响应,另一方面,在高峰期(如有数以万计的并发请求),Nginx比其他Web服务器更快的响应请求。Nginx之所以有这么高的并发处理能力和这么好的性能原因在于Nginx采用了多进程和I/O多路复用(epoll)的底层实现。

(2)配置简单,扩展性强

Nginx的设计极具扩展性,它本身就是由很多模块组成,这些模块的使用可以通过配置文件的配置来添加。这些模块有官方提供的也有第三方提供的模块,如果需要完全可以开发服务自己业务特性的定制模块。

(3)高可靠性

Nginx采用的是多进程模式运行,其中有一个master主进程和N多个worker进程,worker进程的数量我们可以手动设置,每个worker进程之间都是相互独立提供服务,并且master主进程可以在某一个worker进程出错时,快速去”拉起”新的worker进程提供服务。

(4)热部署

现在互联网项目都要求以7*24小时进行服务的提供,针对于这一要求,Nginx也提供了热部署功能,即可以在Nginx不停止的情况下,对Nginx进行文件升级、更新配置和更换日志文件等功能。

特性及常用功能

Nginx提供的基本功能服务从大体上归纳为”基本HTTP服务”、“高级HTTP服务”和”邮件服务”等三大类。

基本HTTP服务

Nginx可以提供基本HTTP服务,可以作为HTTP代理服务器和反向代理服务器,支持通过缓存加速访问,可以完成简单的负载均衡和容错,支持包过滤功能,支持SSL等。

  • 处理静态文件、处理索引文件以及支持自动索引;
  • 提供反向代理服务器,并可以使用缓存加上反向代理,同时完成负载均衡和容错;
  • 提供对FastCGI、memcached等服务的缓存机制,,同时完成负载均衡和容错;
  • 使用Nginx的模块化特性提供过滤器功能。Nginx基本过滤器包括gzip压缩、ranges支持、chunked响应、XSLT、SSI以及图像缩放等。其中针对包含多个SSI的页面,经由FastCGI或反向代理,SSI过滤器可以并行处理。
  • 支持HTTP下的安全套接层安全协议SSL.
  • 支持基于加权和依赖的优先权的HTTP/2

高级HTTP服务

  • 支持基于名字和IP的虚拟主机设置
  • 支持HTTP/1.0中的KEEP-Alive模式和管线(PipeLined)模型连接
  • 自定义访问日志格式、带缓存的日志写操作以及快速日志轮转。
  • 提供3xx~5xx错误代码重定向功能
  • 支持重写(Rewrite)模块扩展
  • 支持重新加载配置以及在线升级时无需中断正在处理的请求
  • 支持网络监控
  • 支持FLV和MP4流媒体传输

邮件服务

Nginx提供邮件代理服务也是其基本开发需求之一,主要包含以下特性:

  • 支持IMPA/POP3代理服务功能
  • 支持内部SMTP代理服务功能

Nginx常用的功能模块

静态资源部署
Rewrite地址重写
    正则表达式
反向代理
负载均衡
    轮询、加权轮询、ip_hash、url_hash、fair
Web缓存
环境部署
    高可用的环境
用户认证模块...

Nginx的核心组成

nginx二进制可执行文件
nginx.conf配置文件
error.log错误的日志记录
access.log访问日志记录

二、安装与配置

1、安装

下载路径:http://nginx.org/download/

安装:https://www.runoob.com/linux/nginx-install-setup.html

安装步骤

(1)安装编译工具及库文件

yum -y install make zlib zlib-devel gcc-c++ libtool  openssl openssl-devel

(2)安装 PCRE

PCRE 作用是让 Nginx 支持 Rewrite 功能。

cd /usr/local/src/
wget http://downloads.sourceforge.net/project/pcre/pcre/8.35/pcre-8.35.tar.gz
tar zxvf pcre-8.35.tar.gz
cd pcre-8.35
./configure
make && make install
pcre-config --version

(3)下载安装nginx

cd /usr/local/src/
wget http://nginx.org/download/nginx-1.6.2.tar.gz
tar zxvf nginx-1.6.2.tar.gz
cd nginx-1.6.2
./configure --prefix=/usr/local/webserver/nginx --with-http_stub_status_module --with-http_ssl_module --with-pcre=/usr/local/src/pcre-8.35
make
make install
ln -s /usr/local/nginx/sbin/nginx /sbin/
/usr/local/webserver/nginx/sbin/nginx -v

Nginx配置成系统服务

把Nginx应用服务设置成为系统服务,方便对Nginx服务的启动和停止等相关操作,具体实现步骤:

(1) 在/usr/lib/systemd/system目录下添加nginx.service,内容如下:

vim /usr/lib/systemd/system/nginx.service
[Unit]
Description=nginx web service
Documentation=http://nginx.org/en/docs/
After=network.target

[Service]
Type=forking
PIDFile=/usr/local/nginx/logs/nginx.pid
ExecStartPre=/usr/local/nginx/sbin/nginx -t -c /usr/local/nginx/conf/nginx.conf
ExecStart=/usr/local/nginx/sbin/nginx
ExecReload=/usr/local/nginx/sbin/nginx -s reload
ExecStop=/usr/local/nginx/sbin/nginx -s stop
PrivateTmp=true

[Install]
WantedBy=default.target

(2)添加完成后如果权限有问题需要进行权限设置

chmod 755 /usr/lib/systemd/system/nginx.service

(3)使用系统命令来操作Nginx服务

启动: systemctl start nginx
停止: systemctl stop nginx
重启: systemctl restart nginx
重新加载配置文件: systemctl reload nginx
查看nginx状态: systemctl status nginx
开机启动: systemctl enable nginx

Nginx命令配置到系统环境

前面我们介绍过Nginx安装目录下的二级制可执行文件nginx的很多命令,要想使用这些命令前提是需要进入sbin目录下才能使用,很不方便,如何去优化,我们可以将该二进制可执行文件加入到系统的环境变量,这样的话在任何目录都可以使用nginx对应的相关命令。具体实现步骤如下:

演示可删除

/usr/local/nginx/sbin/nginx -V
cd /usr/local/nginx/sbin  nginx -V
如何优化???

(1)修改/etc/profile文件

vim /etc/profile
在最后一行添加
export PATH=$PATH:/usr/local/nginx/sbin

(2)使之立即生效

source /etc/profile

(3)执行nginx命令

nginx -V

2、docker方式安装

拉取镜像

docker pull nginx

生成容器并运行

docker run --name nginx -p 80:80 -d nginx

创建挂载目录

mkdir -p /data/nginx

copy文件

docker cp nginx:/etc/nginx/ /data/nginx/
mv /data/nginx/nginx/ /data/nginx/conf/

docker cp nginx:/usr/share/nginx/html/ /data/nginx/

docker cp nginx:/var/log/nginx/ /data/nginx/
mv /data/nginx/nginx/ /data/nginx/logs/

重新生成容器并挂载目录运行

docker stop nginx
docker rm nginx
docker run --name nginx -p 80:80 \
-v /data/nginx/conf/:/etc/nginx/ \
-v /data/nginx/html/:/usr/share/nginx/html/ \
-v /data/nginx/logs/:/var/log/nginx/ \
--privileged=true -d nginx

以下是docker-compose.yml的部署方式

version: '3'

networks:
  nginx_bridge:
    driver: bridge

services:
  nginx:
    image: nginx
    container_name: nginx
    restart: always
    privileged: true
    ports:
      - 80:80
      - 443:443
    volumes:
      - /data/nginx/html:/usr/share/nginx/html
      - ./nginx/conf/nginx.conf:/etc/nginx/nginx.conf:ro
      - ./nginx/conf.d:/etc/nginx/conf.d
      - ./nginx/log:/var/log/nginx
    networks:
      - nginx_bridge

3、安装后新增模块

先查看原有nginx的配置参数并拷贝出来(大写V)

./nginx/sbin/nginx -V

解压nginx源码包(以前安装时的源码包),如果已经删除了可重新下载,版本相同即可

切换到nginx-1.20.1目录下

重新配置configure参数:注意带上原来已经安装的模块,之前 -V 打印的参数+新增模块参数--with-http_sub_module

./configure --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_sub_module --with-http_ssl_module

然后 make 编译一下,注意不要 make install,不然会覆盖你的 nginx 目录,就完蛋了

编译完成的文件在 nginx-1.20.1/objs 目录下的下

把nginx服务先关掉

/usr/local/nginx/sbin/nginx -s stop

备份原来的nginx可执行文件

mv /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx_bak

将编译好的nginx复制到原始nginx的sbin目录

cp ./objs/nginx /usr/local/nginx/sbin

到这里已经安装完毕,可以再执行 /usr/local/nginx/sbin/nginx -V 查看一下nginx的模块情况

二、nginx的启停命令

对于Nginx的启停在linux系统中也有很多种方式,本次介绍两种方式:

  1. Nginx服务的信号控制

  2. Nginx的命令行控制

方式一、信号控制

前面在提到Nginx的高性能,其实也和它的架构模式有关。Nginx默认采用的是多进程的方式来工作的,当将Nginx启动后,我们通过ps -ef | grep nginx命令可以查看master进程和多个worker进程的pid

ps -ef | grep nginx

Nginx后台进程中包含一个master进程和多个worker进程,master进程主要用来管理worker进程,包含接收外界的信息,并将接收到的信号发送给各个worker进程,监控worker进程的状态,当worker进程出现异常退出后,会自动重新启动新的worker进程。而worker进程则是专门用来处理用户请求的,各个worker进程之间是平等的并且相互独立,处理请求的机会也是一样的。

我们现在作为管理员,只需要通过给master进程发送信号就可以来控制Nginx,这个时候我们需要有两个前提条件,一个是要操作的master进程,一个是信号。

(1)要想操作Nginx的master进程,就需要获取到master进程的进程号ID。获取方式简单介绍两个,

方式一:通过ps -ef | grep nginx

方式二:在讲解nginx的./configure的配置参数的时候,有一个参数是--pid-path=PATH默认是/usr/local/nginx/logs/nginx.pid,所以可以通过查看该文件来获取nginx的master进程ID.

(2)信号

信号 作用
TERM/INT 立即关闭整个服务
QUIT “优雅”地关闭整个服务(等所有请求处理完后,在把进程都关闭掉。)
HUP 重读配置文件并使用服务对新配置项生效
USR1 重新打开日志文件,可以用来进行日志切割
USR2 平滑升级到最新版的nginx(先启动新的,在关闭旧的)
WINCH 所有子进程不在接收处理新连接,相当于给work进程发送QUIT指令(只关闭work进程)

调用命令为kill -signal PID

signal:即为信号;PID即为获取到的master线程ID

  1. 发送TERM/INT信号给master进程,会将Nginx服务立即关闭。
kill -TERM PID / kill -TERM `cat /usr/local/nginx/logs/nginx.pid`
kill -INT PID / kill -INT `cat /usr/local/nginx/logs/nginx.pid`

这里用飘号包裹的cat /usr/local/nginx/logs/nginx.pid 是用来获取pid的

  1. 发送QUIT信号给master进程,master进程会控制所有的work进程不再接收新的请求,等所有请求处理完后,在把进程都关闭掉。
kill -QUIT PID / kill -TERM `cat /usr/local/nginx/logs/nginx.pid`
  1. 发送HUP信号给master进程,master进程会把控制旧的work进程不再接收新的请求,等处理完请求后将旧的work进程关闭掉,然后根据nginx的配置文件重新启动新的work进程
kill -HUP PID / kill -TERM `cat /usr/local/nginx/logs/nginx.pid`
  1. 发送USR1信号给master进程,告诉Nginx重新开启日志文件
kill -USR1 PID / kill -TERM `cat /usr/local/nginx/logs/nginx.pid`
  1. 发送USR2信号给master进程,告诉master进程要平滑升级,这个时候,会重新开启对应的master进程和work进程,整个系统中将会有两个master进程,并且新的master进程的PID会被记录在/usr/local/nginx/logs/nginx.pid而之前的旧的master进程PID会被记录在/usr/local/nginx/logs/nginx.pid.oldbin文件中,接着再次发送QUIT信号给旧的master进程,让其处理完请求后再进行关闭
kill -USR2 PID / kill -USR2 `cat /usr/local/nginx/logs/nginx.pid`
kill -QUIT PID / kill -QUIT `cat /usr/local/nginx/logs/nginx.pid.oldbin`

1586368250085

  1. 发送WINCH信号给master进程,让master进程控制不让所有的work进程在接收新的请求了,请求处理完后关闭work进程。注意master进程不会被关闭掉
kill -WINCH PID /kill -WINCH`cat /usr/local/nginx/logs/nginx.pid`

方式二、命令行控制

此方式是通过Nginx安装目录下的sbin下的可执行文件nginx来进行Nginx状态的控制,我们可以先进入nginx目录,后通过./nginx启动

启动

/usr/local/webserver/nginx/sbin/nginx

重新加载配置

/usr/local/webserver/nginx/sbin/nginx -s reload
.\nginx.exe -s reload

重启

/usr/local/webserver/nginx/sbin/nginx -s reopen

关闭

/usr/local/webserver/nginx/sbin/nginx -s stop

等所有请求处理完后,在关闭

/usr/local/webserver/nginx/sbin/nginx -s quit

检查nginx配置文件是否正确

/usr/local/webserver/nginx/sbin/nginx -t

./nginx -h可以用来查看都有哪些参数可以用:

  • -?和-h:显示帮助信息

  • -v:打印版本号信息并退出

  • -V:打印版本号信息和配置信息并退出

  • -t:测试nginx的配置文件语法是否正确并退出

  • -T:测试nginx的配置文件语法是否正确并列出用到的配置文件信息然后退出

  • -q:在配置测试期间禁止显示非错误消息

  • -s:signal信号,后面可以跟 :

    • stop[快速关闭,类似于TERM/INT信号的作用],./nginx -s stop
    • quit[优雅的关闭,类似于QUIT信号的作用]
    • reopen[重新打开日志文件类似于USR1信号的作用]
    • reload[类似于HUP信号的作用]
  • -p:prefix,指定Nginx的prefix路径,(默认为: /usr/local/nginx/)

  • -c:filename,指定Nginx的配置文件路径,(默认为: conf/nginx.conf)

  • -g:用来补充Nginx配置文件,向Nginx服务指定启动时应用全局的配置

三、nginx版本平滑升级

如果想对Nginx的版本进行更新,或者要应用一些新的模块,最简单的做法就是停止当前的Nginx服务,然后开启新的Nginx服务。但是这样会导致在一段时间内,用户是无法访问服务器。为了解决这个问题,我们就需要用到Nginx服务器提供的平滑升级功能。这个也是Nginx的一大特点,使用这种方式,就可以使Nginx在7*24小时不间断的提供服务了。接下来我们分析下需求:

需求:Nginx的版本最开始使用的是Nginx-1.14.2,由于服务升级,需要将Nginx的版本升级到Nginx-1.16.1,要求Nginx不能中断提供服务。

为了应对上述的需求,这里我们给大家提供两种解决方案:

方案一:使用Nginx服务信号完成Nginx的升级

方案二:使用Nginx安装目录的make命令完成升级

环境准备

(1)先准备两个版本的Nginx分别是 1.14.2和1.16.1

(2)使用Nginx源码安装的方式将1.14.2版本安装成功并正确访问

进入安装目录
./configure
make && make install

(3)将Nginx1.16.1进行参数配置和编译,不需要进行安装。

进入安装目录
./configure
make 

方案一、服务信号方式

第一步:将1.14.2版本的sbin目录下的nginx进行备份

cd /usr/local/nginx/sbin
mv nginx nginxold

第二步:将Nginx1.16.1安装目录编译后的objs目录下的nginx文件,拷贝到原来/usr/local/nginx/sbin目录下

cd ~/nginx/core/nginx-1.16.1/objs
cp nginx /usr/local/nginx/sbin

第三步:发送信号USR2给Nginx的1.14.2版本对应的master进程

第四步:发送信号QUIT给Nginx的1.14.2版本对应的master进程

kill -QUIT `more /usr/local/logs/nginx.pid.oldbin`

方案二、make命令

第一步:将1.14.2版本的sbin目录下的nginx进行备份

cd /usr/local/nginx/sbin
mv nginx nginxold

第二步:将Nginx1.16.1安装目录编译后的objs目录下的nginx文件,拷贝到原来/usr/local/nginx/sbin目录下

cd ~/nginx/core/nginx-1.16.1/objs
cp nginx /usr/local/nginx/sbin

第三步:进入到安装目录,执行make upgrade

1581494652284

第四步:查看是否更新成功

./nginx -v

四、核心配置文件

nginx/conf/nginx.conf

当多个相同指令同时配置在不同位置时,会调用最小作用域的指令,即就近原则

基本结构

指令名    指令值;  #全局块,主要设置Nginx服务器整体运行的配置指令

# events块,主要设置,Nginx服务器与用户的网络连接,这一部分对Nginx服务器的性能影响较大
events {     
    指令名    指令值;
}
#http块,是Nginx服务器配置中的重要部分,代理、缓存、日志记录、第三方模块配置...             
http {        
    指令名    指令值;
    server { #server块,是Nginx配置和虚拟主机相关的内容
        指令名    指令值;
        location / { 
        #location块,基于Nginx服务器接收请求字符串与location后面的值进行匹配,对特定请求进行处理
            指令名    指令值;
        }
    }
    ...
}

简单小结下:

nginx.conf配置文件中默认有三大块:全局块、events块、http块

http块中可以配置多个server块,每个server块又可以配置多个location块。

1、全局块

(1)user权限指令

user:用于配置运行Nginx服务器的worker进程的用户和用户组。

语法 user user [group]
默认值 nobody
位置 全局块

该属性也可以在编译的时候指定,语法如下./configure --user=user --group=group,如果两个地方都进行了设置,最终生效的是配置文件中的配置。

在全局块中设置一个用户信息”www”,如下

user www;

当配置文件中添加这个指令后,nginx只能访问该用户所属的文件,可用 ll 命令查看被访问资源文件拥有者,可用ps -ef | grep nginx查看当前nginx进程指定的用户。当用户访问的服务器资源文件的拥有者不是nginx.conf配置文件中指定的用户时,报403权限不足错误。

可通过以下shell命令创建一个用户,此时会在

useradd www

默认root用户的文件夹是/root,而其他用户的文件夹在/home目录下。在/home目录下执行ll命令即可查看到文件夹的拥有者

[root@iZwz98s1wklbts28xszgzcZ home]# ll
total 12
drwx------ 3 git    git    4096 May 26 19:44 git
drwx------ 3 rewind rewind 4096 Sep 14 21:25 rewind
drwx------ 2 www    www    4096 May 26 17:51 www

综上所述,使用user指令可以指定启动运行工作进程的用户及用户组,这样对于系统的权限访问控制的更加精细,也更加安全。

(2)work process指令

该指令需重启nginx生效。

master_process:用来指定是否开启工作进程。

语法 master_process on|off;
默认值 master_process on;
位置 全局块

worker_processes:用于配置Nginx生成工作进程的数量(master_process 必须为on才生效),这个是Nginx服务器实现并发处理服务的关键所在。理论上来说workder process的值越大,可以支持的并发处理量也越多,但事实上这个值的设定是需要受到来自服务器自身的限制,建议将该值和服务器CPU的内核数保存一致

语法 worker_processes num/auto;
默认值 1
位置 全局块

如果将worker_processes设置成2,通过ps -ef | grep nginx即可查看到2个工作进程

(3)其他指令

daemon:设定Nginx是否以守护进程的方式启动。

守护式进程是linux后台执行的一种服务进程,特点是独立于控制终端,不会随着终端关闭而停止。

语法 daemon on|off;
默认值 daemon on;
位置 全局块

pid:用来配置Nginx当前master进程的进程号ID存储的文件路径。

语法 pid file;
默认值 默认为:/usr/local/nginx/logs/nginx.pid
位置 全局块

该属性可以通过./configure --pid-path=PATH来指定

error_log:用来配置Nginx的错误日志存放路径

语法 error_log file [日志级别];
默认值 error_log logs/error.log error;
位置 全局块、http、server、location

该属性可以通过./configure --error-log-path=PATH来指定

其中日志级别的值有:debug|info|notice|warn|error|crit|alert|emerg,翻译过来为试|信息|通知|警告|错误|临界|警报|紧急,这块建议大家设置的时候不要设置成info以下的等级,因为会带来大量的磁盘I/O消耗,影响Nginx的性能。

(5)include:用来引入其他配置文件,使Nginx的配置更加灵活

语法 include file;
默认值
位置 any

引入main.conf 配置文件,与nginx在同级目录,内容和格式与nginx.conf一致。

include main.conf;

2、events块

(0)配置案例

events{
    # 设置Nginx网络连接序列化
    accept_mutex on;
    # 设置是否允许同时接收多个网络连接
    multi_accept on;
    # 配置单个worker进程最大的连接数
    worker_commections 1024;
    # 设置Nginx服务器选择哪种事件驱动来处理网络消息
    use epoll;
}

(1)accept_mutex:用来设置Nginx网络连接序列化

语法 accept_mutex on|off;
默认值 accept_mutex on;
位置 events

这个配置主要可以用来解决常说的”惊群”问题。大致意思是在某一个时刻,客户端发来一个请求连接,Nginx后台是以多进程的工作模式,也就是说有多个worker进程会被同时唤醒,但是最终只会有一个进程可以获取到连接,如果每次唤醒的进程数目太多,就会影响Nginx的整体性能。如果将上述值设置为on(开启状态),将会对多个Nginx进程接收连接进行序列号,一个个来唤醒接收,就防止了多个进程对连接的争抢。

(2)multi_accept:用来设置是否允许同时接收多个网络连接,建议为on

语法 multi_accept on|off;
默认值 multi_accept off;
位置 events

如果multi_accept被禁止了,nginx一个工作进程只能同时接受一个新的连接。否则,一个工作进程可以同时接受所有的新连接

(3)worker_connections:用来配置单个worker进程最大的连接数

语法 worker_connections number;
默认值 worker_commections 512;
位置 events

这里的连接数不仅仅包括和前端用户建立的连接数,而是包括所有可能的连接数。另外,number值不能大于操作系统支持打开的最大文件句柄数量。

(4)use:用来设置Nginx服务器选择哪种事件驱动来处理网络消息。推荐值epoll

语法 use method;
默认值 根据操作系统定
位置 events

注意:此处所选择事件处理模型是Nginx优化部分的一个重要内容,method的可选值有select/poll/epoll/kqueue等,之前在准备centos环境的时候,我们强调过要使用linux内核在2.6以上,就是为了能使用epoll函数来优化Nginx。

另外这些值的选择,我们也可以在编译的时候使用

--with-select_module--without-select_module

--with-poll_module --without-poll_module来设置是否需要将对应的事件驱动模块编译到Nginx的内核。

3、http块

(1)定义MIME-Type

我们都知道浏览器中可以显示的内容有HTML、XML、GIF等种类繁多的文件、媒体等资源,浏览器为了区分这些资源,就需要使用MIME Type。所以说MIME Type是网络资源的媒体类型。Nginx作为web服务器,也需要能够识别前端请求的资源类型。

在Nginx的配置文件中,默认有两行配置

# 引入外部配置文件,该文件定义了可使用的mime type
include mime.types;
# 配置mime类型为二进制流,在浏览器表现为下载文件
default_type application/octet-stream;

default_type:用来配置Nginx响应前端请求默认的MIME类型。

语法 default_type mime-type;
默认值 default_type text/plain;
位置 http、server、location

在default_type之前还有一句include mime.types,include之前我们已经介绍过,相当于把mime.types文件中MIMT类型与相关类型文件的文件后缀名的对应关系加入到当前的配置文件中。

有些时候请求某些接口的时候需要返回指定的文本字符串或者json字符串,如果逻辑非常简单或者干脆是固定的字符串,那么可以使用nginx快速实现,这样就不用编写程序响应请求了,可以减少服务器资源占用并且响应性能非常快。

如何实现:

location /get_text {
    #这里也可以设置成text/plain
    default_type text/html;
    return 200 "This is nginx's text";
}
location /get_json{
    default_type application/json;
    return 200 '{"name":"TOM","age":18}';
}

(2)自定义服务日志

Nginx中日志的类型分access.log、error.log。

access.log:用来记录用户所有的访问请求。

error.log:记录nginx本身运行时的错误信息,不会记录用户的访问请求。

Nginx服务器支持对服务日志的格式、大小、输出等进行设置,需要使用到两个指令,分别是access_log和log_format指令。

(1)access_log:用来设置用户访问日志的相关属性。

语法 access_log path[format[buffer=size]]
默认值 access_log logs/access.log combined;
位置 http, server, location

(2)log_format:用来指定日志的输出格式。

语法 log_format name [escape=default|json|none] string….;
默认值 log_format combined “…”;
位置 http

(3)其他配置指令

(1)sendfile:用来设置Nginx服务器是否使用sendfile()传输文件,该属性可以大大提高Nginx处理静态资源的性能,建议值on

语法 sendfile on|off;
默认值 sendfile off;
位置 http、server、location

(2)keepalive_timeout:用来设置长连接的超时时间。

》为什么要使用keepalive?

我们都知道HTTP是一种无状态协议,客户端向服务端发送一个TCP请求,服务端响应完毕后断开连接。
如何客户端向服务端发送多个请求,每个请求都需要重新创建一次连接,效率相对来说比较多,使用keepalive模式,可以告诉服务器端在处理完一个请求后保持这个TCP连接的打开状态,若接收到来自这个客户端的其他请求,服务端就会利用这个未被关闭的连接,而不需要重新创建一个新连接,提升效率,但是这个连接也不能一直保持,这样的话,连接如果过多,也会是服务端的性能下降,这个时候就需要我们进行设置其的超时时间。
语法 keepalive_timeout time;
默认值 keepalive_timeout 75s;
位置 http、server、location

(3)keepalive_requests:用来设置一个keep-alive连接使用的次数。达到指定次数即断开

语法 keepalive_requests number;
默认值 keepalive_requests 100;
位置 http、server、location

(4)server块和location块

详见本文《五、静态资源部署》

server {
    listen       80;     #监听端口
    server_name  localhost;        #服务域名或ip
    location / {    #匹配路径
        root   html;    #资源文件目录
        index  index.html index.htm;    #首页
    }

    error_page   500 502 503 504 404  /50x.html;    #需跳转错误页面的错误码
    location = /50x.html {
        root   html;    
    }
}

4、实操案例

(1)有如下访问:
    http://192.168.200.133:8081/server1/location1
        访问的是:index_sr1_location1.html
    http://192.168.200.133:8081/server1/location2
        访问的是:index_sr1_location2.html
    http://192.168.200.133:8082/server2/location1
        访问的是:index_sr2_location1.html
    http://192.168.200.133:8082/server2/location2
        访问的是:index_sr2_location2.html
(2)如果访问的资源不存在,
    返回自定义的404页面
(3)将/server1和/server2的配置使用不同的配置文件分割
    将文件放到/home/www/conf.d目录下,然后使用include进行合并
(4)为/server1和/server2各自创建一个访问日志文件

主配置文件:nginx.conf

##全局块 begin##
#配置允许运行Nginx工作进程的用户和用户组
user www;
#配置运行Nginx进程生成的worker进程数
worker_processes 2;
#配置Nginx服务器运行对错误日志存放的路径
error_log logs/error.log;
#配置Nginx服务器允许时记录Nginx的master进程的PID文件路径和名称
pid logs/nginx.pid;
#配置Nginx服务是否以守护进程方法启动
#daemon on;
##全局块 end##

##events块 begin##
events{
    #设置Nginx网络连接序列化
    accept_mutex on;
    #设置Nginx的worker进程是否可以同时接收多个请求
    multi_accept on;
    #设置Nginx的worker进程最大的连接数
    worker_connections 1024;
    #设置Nginx使用的事件驱动模型
    use epoll;
}
##events块 end##
##http块 start##
http{
    #定义MIME-Type
    include mime.types;
    default_type application/octet-stream;
    #配置允许使用sendfile方式运输
    sendfile on;
    #配置连接超时时间
    keepalive_timeout 65;
    #配置请求处理日志格式
    log_format server1 '===>server1 access log';
    log_format server2 '===>server2 access log';
    ##server块 开始##
    include /home/www/conf.d/*.conf;
    ##server块 结束##
}
##http块 end##

server1.conf

server{
        #配置监听端口和主机名称
        listen 8081;
        server_name localhost;
        #配置请求处理日志存放路径
        access_log /home/www/myweb/server1/logs/access.log server1;
        #配置错误页面
        error_page 404 /404.html;
        #配置处理/server1/location1请求的location
        location /server1/location1{
            root /home/www/myweb;
            index index_sr1_location1.html;
        }
        #配置处理/server1/location2请求的location
        location /server1/location2{
            root /home/www/myweb;
            index index_sr1_location2.html;
        }
        #配置错误页面转向
        location = /404.html {
            root /home/www/myweb;
            index 404.html;
        }
}

server2.conf

server{
        #配置监听端口和主机名称
        listen 8082;
        server_name localhost;
        #配置请求处理日志存放路径
        access_log /home/www/myweb/server2/logs/access.log server2;
        #配置错误页面,对404.html做了定向配置
        error_page 404 /404.html;
        #配置处理/server1/location1请求的location
        location /server2/location1{
            root /home/www/myweb;
            index index_sr2_location1.html;
        }
        #配置处理/server2/location2请求的location
        location /server2/location2{
            root /home/www/myweb;
            index index_sr2_location2.html;
        }
        #配置错误页面转向
        location = /404.html {
            root /home/www/myweb;
            index 404.html;
        }
}

五、静态资源部署

1、指令

(1)listen

listen:用来配置监听端口。

语法 listen address[:port] [default_server]…;
listen port [default_server]…;
默认值 listen *:80 | *:8000
位置 server

listen的设置比较灵活,我们通过几个例子来把常用的设置方式熟悉下:

listen 127.0.0.1:8000; // listen localhost:8000 监听指定的IP和端口
listen 127.0.0.1;    监听指定IP的所有端口
listen 8000;    监听指定端口上的连接
listen *:8000;    监听指定端口上的连接

default_server属性是标识符,用来将此虚拟主机设置成默认主机。所谓的默认主机指的是如果没有匹配到对应的address:port,则会默认执行的。如果不指定默认使用的是第一个server。(保底页面)

server{
    listen 8080;
    server_name 127.0.0.1;
    location /{
        root html;
        index index.html;
    }
}
server{
    listen 8080 default_server;
    server_name localhost;
    default_type text/plain;
    return 444 'This is a error request';
}

(2)server_name

server_name:用来设置虚拟主机服务名称。

127.0.0.1 、 localhost 、域名[www.baidu.com | www.jd.com]

语法 server_name name …;
name可以提供多个中间用空格分隔
默认值 server_name “”;
位置 server

关于server_name的配置方式有三种,分别是:

精确匹配
通配符匹配
正则表达式匹配

配置方式一:精确匹配

如:

server {
    listen 80;
    server_name www.itcast.cn www.itheima.cn;
    ...
}

补充小知识点:

hosts是一个没有扩展名的系统文件,可以用记事本等工具打开,其作用就是将一些常用的网址域名与其对应的IP地址建立一个关联“数据库”,当用户在浏览器中输入一个需要登录的网址时,系统会首先自动从hosts文件中寻找对应的IP地址,一旦找到,系统会立即打开对应网页,如果没有找到,则系统会再将网址提交DNS域名解析服务器进行IP地址的解析。

windows:C:\Windows\System32\drivers\etc

centos:/etc/hosts

因为域名是要收取一定的费用,所以我们可以使用修改hosts文件来制作一些虚拟域名来使用。需要修改 /etc/hosts文件来添加

vim /etc/hosts
127.0.0.1 www.itcast.cn
127.0.0.1 www.itheima.cn

配置方式二:使用通配符配置

server_name中支持通配符”*”,但需要注意的是通配符不能出现在域名的中间,只能出现在首段或尾段,如:

server {
    listen 80;
    server_name  *.itcast.cn    www.itheima.*;
    # www.itcast.cn abc.itcast.cn www.itheima.cn www.itheima.com
    ...
}

下面的配置就会报错

server {
    listen 80;
    server_name  www.*.cn www.itheima.c*
    ...
}

配置三:使用正则表达式配置

server_name中可以使用正则表达式,并且使用~作为正则表达式字符串的开始标记。

常见的正则表达式

代码 说明
^ 匹配搜索字符串开始位置
$ 匹配搜索字符串结束位置
. 匹配除换行符\n之外的任何单个字符
\ 转义字符,将下一个字符标记为特殊字符
[xyz] 字符集,与任意一个指定字符匹配
[a-z] 字符范围,匹配指定范围内的任何字符
\w 与以下任意字符匹配 A-Z a-z 0-9 和下划线,等效于[A-Za-z0-9_]
\d 数字字符匹配,等效于[0-9]
{n} 正好匹配n次
{n,} 至少匹配n次
{n,m} 匹配至少n次至多m次
* 零次或多次,等效于{0,}
+ 一次或多次,等效于{1,}
? 零次或一次,等效于{0,1}

配置如下:

server{
        listen 80;
        server_name ~^www\.(\w+)\.com$;
        default_type text/plain;
        return 200 $1  $2 ..;
}
注意 ~后面不能加空格,括号可以取值
匹配执行顺序

由于server_name指令支持通配符和正则表达式,因此在包含多个虚拟主机的配置文件中,可能会出现一个名称被多个虚拟主机的server_name匹配成功,当遇到这种情况,当前的请求交给谁来处理呢?

server{
    listen 80;
    server_name ~^www\.\w+\.com$;
    default_type text/plain;
    return 200 'regex_success';
}

server{
    listen 80;
    server_name www.itheima.*;
    default_type text/plain;
    return 200 'wildcard_after_success';
}

server{
    listen 80;
    server_name *.itheima.com;
    default_type text/plain;
    return 200 'wildcard_before_success';
}

server{
    listen 80;
    server_name www.itheima.com;
    default_type text/plain;
    return 200 'exact_success';
}

server{
    listen 80 default_server;
    server_name _;
    default_type text/plain;
    return 444 'default_server not found server';
}

结论:

exact_success
wildcard_before_success
wildcard_after_success
regex_success
default_server not found server!!
No1:准确匹配server_name

No2:通配符在开始时匹配server_name成功

No3:通配符在结束时匹配server_name成功

No4:正则表达式匹配server_name成功

No5:被默认的default_server处理,如果没有指定默认找第一个server

(3)location

server{
    listen 80;
    server_name localhost;
    location / {

    }
    location /abc{

    }
    ...
}

location:用来设置请求的URI

语法 location [ = | ~ | * | ^ |@ ] uri{…}
默认值
位置 server,location

uri变量是待匹配的请求字符串,可以不包含正则表达式,也可以包含正则表达式,那么nginx服务器在搜索匹配location的时候,是先使用不包含正则表达式进行匹配,找到一个匹配度最高的一个,然后在通过包含正则表达式的进行匹配,如果能匹配到直接访问,匹配不到,就使用刚才匹配度最高的那个location来处理请求。

属性介绍:

不带符号,要求必须以指定模式开始

server {
    listen 80;
    server_name 127.0.0.1;
    location /abc{
        default_type text/plain;
        return 200 "access success";
    }
}
以下访问都是正确的
http://192.168.200.133/abc
http://192.168.200.133/abc?p1=TOM
http://192.168.200.133/abc/
http://192.168.200.133/abcdef

= : 用于不包含正则表达式的uri前,必须与指定的模式精确匹配

server {
    listen 80;
    server_name 127.0.0.1;
    location =/abc{
        default_type text/plain;
        return 200 "access success";
    }
}
可以匹配到
http://192.168.200.133/abc
http://192.168.200.133/abc?p1=TOM
匹配不到
http://192.168.200.133/abc/
http://192.168.200.133/abcdef

~ : 用于表示当前uri中包含了正则表达式,并且区分大小写
~*: 用于表示当前uri中包含了正则表达式,并且不区分大小写

换句话说,如果uri包含了正则表达式,需要用上述两个符合来标识

server {
    listen 80;
    server_name 127.0.0.1;
    location ~^/abc\w${
        default_type text/plain;
        return 200 "access success";
    }
}
server {
    listen 80;
    server_name 127.0.0.1;
    location ~*^/abc\w${
        default_type text/plain;
        return 200 "access success";
    }
}

^~: 用于不包含正则表达式的uri前,功能和不加符号的一致,唯一不同的是,如果模式匹配,那么就停止搜索其他模式了。

server {
    listen 80;
    server_name 127.0.0.1;
    location ^~/abc{
        default_type text/plain;
        return 200 "access success";
    }
}

(4)root / alias

root:设置请求的根目录

语法 root path;
默认值 root html;
位置 http、server、location

path为Nginx服务器接收到请求以后查找资源的根目录路径。

alias:用来更改location的URI

语法 alias path;
默认值
位置 location

path为修改后的根路径。

以上两个指令都可以来指定访问资源的路径,那么这两者之间的区别是什么?

举例说明:

(1)在/usr/local/nginx/html目录下创建一个 images目录,并在目录下放入一张图片mv.png图片

location /images {
    root /usr/local/nginx/html;
}

访问图片的路径为:

http://192.168.200.133/images/mv.png

(2)如果把root改为alias

location /images {
    alias /usr/local/nginx/html;
}

再次访问上述地址,页面会出现404的错误,查看错误日志会发现是因为地址不对,所以验证了:

root的处理结果是: root路径+location路径
/usr/local/nginx/html/images/mv.png
alias的处理结果是:使用alias路径替换location路径
/usr/local/nginx/html/images

需要在alias后面路径改为

location /images {
    alias /usr/local/nginx/html/images;
}

(3)如果location路径是以/结尾,则alias也必须是以/结尾,root没有要求

将上述配置修改为

location /images/ {
    alias /usr/local/nginx/html/images;
}

访问就会出问题,查看错误日志还是路径不对,所以需要把alias后面加上 /

小结:

root的处理结果是: root路径+location路径
alias的处理结果是:使用alias路径替换location路径
alias是一个目录别名的定义,root则是最上层目录的含义。
如果location路径是以/结尾,则alias也必须是以/结尾,root没有要求

(5)index

index:设置网站的默认首页

语法 index file …;
默认值 index index.html;
位置 http、server、location

index后面可以跟多个设置,如果访问的时候没有指定具体访问的资源,则会依次进行查找,找到第一个为止。

举例说明:

location / {
    root /usr/local/nginx/html;
    index index.html index.htm;
}
访问该location的时候,可以通过 http://ip:port/,地址后面如果不添加任何内容,则默认依次访问index.html和index.htm,找到第一个来进行返回

(6)error_page

error_page:设置网站的错误页面

语法 error_page code … [=[response]] uri;
默认值
位置 http、server、location……

当出现对应的响应code后,如何来处理。

举例说明:

(1)可以指定具体跳转的地址

server {
    error_page 404 http://www.itcast.cn;
}

(2)可以指定重定向地址

server{
    error_page 404 /50x.html;
    error_page 500 502 503 504 /50x.html;
    location =/50x.html{
        root html;
    }
}

(3)使用location的@符合完成错误信息展示,用于匹配到指定的location块

server{
    error_page 404 @jump_to_error;
    location @jump_to_error {
        default_type text/plain;
        return 404 'Not Found Page...';
    }
}

可选项=[response]的作用是用来将相应代码更改为另外一个,用于更改状态码

server{
    error_page 404 =200 /50x.html;
    location =/50x.html{
        root html;
    }
}
这样的话,当返回404找不到对应的资源的时候,在浏览器上可以看到,最终返回的状态码是200,这块需要注意下,编写error_page后面的内容,404后面需要加空格,200前面不能加空格

2、静态资源优化配置

Nginx对静态资源如何进行优化配置。这里从三个属性配置进行优化:

sendfile on;
tcp_nopush on;
tcp_nodeplay on;

(1)sendfile,用来开启高效的文件传输模式。

语法 sendfile on |off;
默认值 sendfile off;
位置 http、server、location…

请求静态资源的过程:客户端通过网络接口向服务端发送请求,操作系统将这些客户端的请求传递给服务器端应用程序,服务器端应用程序会处理这些请求,请求处理完成以后,操作系统还需要将处理得到的结果通过网络适配器传递回去。

如:

server {
    listen 80;
    server_name localhost;
    location / {
        root html;
        index index.html;
    }
}
在html目录下有一个welcome.html页面,访问地址
http://192.168.200.133/welcome.html

(2)tcp_nopush:该指令必须在sendfile打开的状态下才会生效,主要是用来提升网络包的传输’效率’

语法 tcp_nopush on|off;
默认值 tcp_nopush off;
位置 http、server、location

(3)tcp_nodelay:该指令必须在keep-alive连接开启的情况下才生效,来提高网络包传输的’实时性’

语法 tcp_nodelay on|off;
默认值 tcp_nodelay on;
位置 http、server、location

经过刚才的分析,”tcp_nopush”和”tcp_nodelay“看起来是”互斥的”,那么为什么要将这两个值都打开,这个大家需要知道的是在linux2.5.9以后的版本中两者是可以兼容的,三个指令都开启的好处是,sendfile可以开启高效的文件传输模式,tcp_nopush开启可以确保在发送到客户端之前数据包已经充分“填满”, 这大大减少了网络开销,并加快了文件发送的速度。 然后,当它到达最后一个可能因为没有“填满”而暂停的数据包时,Nginx会忽略tcp_nopush参数, 然后,tcp_nodelay强制套接字发送数据。由此可知,TCP_NOPUSH可以与TCP_NODELAY一起设置,它比单独配置TCP_NODELAY具有更强的性能。所以我们可以使用如下配置来优化Nginx静态资源的处理

3、静态资源压缩

在Nginx的配置文件中可以通过配置gzip来对静态资源进行压缩,相关的指令可以配置在http块、server块和location块中,Nginx可以通过

ngx_http_gzip_module模块
ngx_http_gzip_static_module模块
ngx_http_gunzip_module模块

Gzip模块配置指令

接下来所学习的指令都来自ngx_http_gzip_module模块,该模块会在nginx安装的时候内置到nginx的安装环境中,也就是说我们可以直接使用这些指令。

  1. gzip指令:该指令用于开启或者关闭gzip功能
语法 gzip on|off;
默认值 gzip off;
位置 http、server、location…

注意只有该指令为打开状态,下面的指令才有效果

http{
   gzip on;
}
  1. gzip_types指令:该指令可以根据响应页的MIME类型选择性地开启Gzip压缩功能
语法 gzip_types mime-type …;
默认值 gzip_types text/html;
位置 http、server、location

所选择的值可以从mime.types文件中进行查找,也可以使用”*”代表所有。

http{
    gzip_types application/javascript;
}
  1. gzip_comp_level指令:该指令用于设置Gzip压缩程度,级别从1-9,1表示要是程度最低,要是效率最高,9刚好相反,压缩程度最高,但是效率最低最费时间。
语法 gzip_comp_level level;
默认值 gzip_comp_level 1;
位置 http、server、location
http{
    gzip_comp_level 6;
}
  1. gzip_vary指令:该指令用于设置使用Gzip进行压缩发送是否携带“Vary:Accept-Encoding”头域的响应头部。主要是告诉接收方,所发送的数据经过了Gzip压缩处理
语法 gzip_vary on|off;
默认值 gzip_vary off;
位置 http、server、location

1587361606028

  1. gzip_buffers指令:该指令用于处理请求压缩的缓冲区数量和大小。
语法 gzip_buffers number size;
默认值 gzip_buffers 32 4k|16 8k;
位置 http、server、location

其中number:指定Nginx服务器向系统申请缓存空间个数,size指的是每个缓存空间的大小。主要实现的是申请number个每个大小为size的内存空间。这个值的设定一般会和服务器的操作系统有关,所以建议此项不设置,使用默认值即可。

gzip_buffers 4 16K;      #缓存空间大小
  1. gzip_disable指令:针对不同种类客户端发起的请求,可以选择性地开启和关闭Gzip功能。
语法 gzip_disable regex …;
默认值
位置 http、server、location

regex:根据客户端的浏览器标志(user-agent)来设置,支持使用正则表达式。指定的浏览器标志不使用Gzip.该指令一般是用来排除一些明显不支持Gzip的浏览器。

gzip_disable "MSIE [1-6]\.";
  1. gzip_http_version指令:针对不同的HTTP协议版本,可以选择性地开启和关闭Gzip功能。
语法 gzip_http_version 1.0|1.1;
默认值 gzip_http_version 1.1;
位置 http、server、location

该指令是指定使用Gzip的HTTP最低版本,该指令一般采用默认值即可。

  1. gzip_min_length指令:该指令针对传输数据的大小,可以选择性地开启和关闭Gzip功能
语法 gzip_min_length length;
默认值 gzip_min_length 20;
位置 http、server、location
nignx计量大小的单位:bytes[字节] / kb[千字节] / M[兆]
例如: 1024 / 10k|K / 10m|M

Gzip压缩功能对大数据的压缩效果明显,但是如果要压缩的数据比较小的化,可能出现越压缩数据量越大的情况,因此我们需要根据响应内容的大小来决定是否使用Gzip功能,响应页面的大小可以通过头信息中的Content-Length来获取。但是如何使用了Chunk编码动态压缩,该指令将被忽略。建议设置为1K或以上。

  1. gzip_proxied指令:该指令设置是否对服务端返回的结果进行Gzip压缩。
语法 gzip_proxied off|expired|no-cache|
no-store|private|no_last_modified|no_etag|auth|any;
默认值 gzip_proxied off;
位置 http、server、location

off - 关闭Nginx服务器对后台服务器返回结果的Gzip压缩
expired - 启用压缩,如果header头中包含 “Expires” 头信息
no-cache - 启用压缩,如果header头中包含 “Cache-Control:no-cache” 头信息
no-store - 启用压缩,如果header头中包含 “Cache-Control:no-store” 头信息
private - 启用压缩,如果header头中包含 “Cache-Control:private” 头信息
no_last_modified - 启用压缩,如果header头中不包含 “Last-Modified” 头信息
no_etag - 启用压缩 ,如果header头中不包含 “ETag” 头信息
auth - 启用压缩 , 如果header头中包含 “Authorization” 头信息
any - 无条件启用压缩

Gzip压缩功能的实例配置

gzip on;                #开启gzip功能
gzip_types *;          #压缩源文件类型,根据具体的访问资源类型设定
gzip_comp_level 6;      #gzip压缩级别
gzip_min_length 1024; #进行压缩响应页面的最小长度,content-length
gzip_buffers 4 16K;      #缓存空间大小
gzip_http_version 1.1; #指定压缩响应所需要的最低HTTP请求版本
gzip_vary  on;          #往头信息中添加压缩标识
gzip_disable "MSIE [1-6]\."; #对IE6以下的版本都不进行压缩
gzip_proxied  off; #nginx作为反向代理压缩服务端返回数据的条件

这些配置在很多地方可能都会用到,所以我们可以将这些内容抽取到一个配置文件中,然后通过include指令把配置文件再次加载到nginx.conf配置文件中,方法使用。

nginx_gzip.conf

gzip on;
gzip_types *;
gzip_comp_level 6;
gzip_min_length 1024;
gzip_buffers 4 16K;
gzip_http_version 1.1;
gzip_vary  on;
gzip_disable "MSIE [1-6]\.";
gzip_proxied  off;

nginx.conf

include nginx_gzip.conf

Gzip和sendfile共存问题

前面在讲解sendfile的时候,提到过,开启sendfile以后,在读取磁盘上的静态资源文件的时候,可以减少拷贝的次数,可以不经过用户进程将静态文件通过网络设备发送出去,但是Gzip要想对资源压缩,是需要经过用户进程进行操作的。所以如何解决两个设置的共存问题。

可以使用ngx_http_gzip_static_module模块的gzip_static指令来解决。

gzip_static指令

gzip_static: 检查与访问资源同名的.gz文件时,response中以gzip相关的header返回.gz文件的内容。

语法 gzip_static on | off | always;
默认值 gzip_static off;
位置 http、server、location

添加上述命令后,会报一个错误,unknown directive "gzip_static"主要的原因是Nginx默认是没有添加ngx_http_gzip_static_module模块。如何来添加?

添加模块到Nginx的实现步骤

(1)查询当前Nginx的配置参数

nginx -V

(2)将nginx安装目录下sbin目录中的nginx二进制文件进行更名

cd /usr/local/nginx/sbin
mv nginx nginxold

(3) 进入Nginx的安装目录

cd /root/nginx/core/nginx-1.16.1

(4)执行make clean清空之前编译的内容

make clean

(5)使用configure来配置参数

./configure --with-http_gzip_static_module

(6)使用make命令进行编译

make

(7) 将objs目录下的nginx二进制执行文件移动到nginx安装目录下的sbin目录中

mv objs/nginx /usr/local/nginx/sbin

(8)执行更新命令

make upgrade
gzip_static测试使用

(1)直接访问http://192.168.200.133/jquery.js

1587932106429

(2)使用gzip命令进行压缩

cd /usr/local/nginx/html
gzip jquery.js

(3)再次访问http://192.168.200.133/jquery.js

1587932300006

4、静态资源的缓存处理

什么是web缓存

Web缓存是指一个Web资源(如html页面,图片,js,数据等)存在于Web服务器和客户端(浏览器)之间的副本。缓存会根据进来的请求保存输出内容的副本;当下一个请求来到的时候,如果是相同的URL,缓存会根据缓存机制决定是直接使用副本响应访问请求,还是向源服务器再次发送请求。比较常见的就是浏览器会缓存访问过网站的网页,当再次访问这个URL地址的时候,如果网页没有更新,就不会再次下载网页,而是直接使用本地缓存的网页。只有当网站明确标识资源已经更新,浏览器才会再次下载网页

web缓存的种类

客户端缓存
    浏览器缓存
服务端缓存
    Nginx / Redis / Memcached等

浏览器缓存

是为了节约网络的资源加速浏览,浏览器在用户磁盘上对最近请求过的文档进行存储,当访问者再次请求这个页面时,浏览器就可以从本地磁盘显示文档,这样就可以加速页面的阅览.

浏览器缓存的执行流程

HTTP协议中和页面缓存相关的字段,我们先来认识下:

header 说明
Expires 缓存过期的日期和时间
Cache-Control 设置和缓存相关的配置信息
Last-Modified 请求资源最后修改时间
ETag 请求变量的实体标签的当前值,比如文件的MD5值

(1)用户首次通过浏览器发送请求到服务端获取数据,客户端是没有对应的缓存,所以需要发送request请求来获取数据;

(2)服务端接收到请求后,获取服务端的数据及服务端缓存的允许后,返回200的成功状态码并且在响应头上附上对应资源以及缓存信息;

(3)当用户再次访问相同资源的时候,客户端会在浏览器的缓存目录中查找是否存在响应的缓存文件

(4)如果没有找到对应的缓存文件,则走(2)步

(5)如果有缓存文件,接下来对缓存文件是否过期进行判断,过期的判断标准是(Expires),

(6)如果没有过期,则直接从本地缓存中返回数据进行展示(强缓存)

(7)如果Expires过期,接下来需要判断缓存文件是否发生过变化

(8)判断的标准有两个,一个是ETag(Entity Tag),一个是Last-Modified

(9)判断结果是未发生变化,则服务端返回304,直接从缓存文件中获取数据(弱缓存)

(10)如果判断是发生了变化,重新从服务端获取数据,并根据缓存协商(服务端所设置的是否需要进行缓存数据的设置)来进行数据缓存。

浏览器缓存相关指令

Nginx需要进行缓存相关设置,就需要用到如下的指令

expires指令

expires:该指令用来控制页面缓存的作用。可以通过该指令控制HTTP应答中的“Expires”和”Cache-Control”

语法 expires [modified] time
expires epoch|max|off;
默认值 expires off;
位置 http、server、location

time:可以整数也可以是负数,指定过期时间,如果是负数,Cache-Control则为no-cache,如果为整数或0,则Cache-Control的值为max-age=time;

epoch: 指定Expires的值为’1 January,1970,00:00:01 GMT’(1970-01-01 00:00:00),Cache-Control的值no-cache

max:指定Expires的值为’31 December2037 23:59:59GMT’ (2037-12-31 23:59:59) ,Cache-Control的值为10年

off:默认不缓存。

add_header指令

add_header指令是用来添加指定的响应头和响应值。

语法 add_header name value [always];
默认值
位置 http、server、location…

Cache-Control作为响应头信息,可以设置如下值:

缓存响应指令:

Cache-control: must-revalidate
Cache-control: no-cache
Cache-control: no-store
Cache-control: no-transform
Cache-control: public
Cache-control: private
Cache-control: proxy-revalidate
Cache-Control: max-age=<seconds>
Cache-control: s-maxage=<seconds>
指令 说明
must-revalidate 可缓存但必须再向源服务器进行确认
no-cache 缓存前必须确认其有效性
no-store 不缓存请求或响应的任何内容
no-transform 代理不可更改媒体类型
public 可向任意方提供响应的缓存
private 仅向特定用户返回响应
proxy-revalidate 要求中间缓存服务器对缓存的响应有效性再进行确认
max-age=<秒> 响应最大Age值
s-maxage=<秒> 公共缓存服务器响应的最大Age值

max-age=[秒]:

5、静态资源防盗链

什么是资源盗链

资源盗链指的是此内容不在自己服务器上,而是通过技术手段,绕过别人的限制将别人的内容放到自己页面上最终展示给用户。以此来盗取大网站的空间和流量。简而言之就是用别人的东西成就自己的网站。

Nginx防盗链的实现原理:

了解防盗链的原理之前,我们得先学习一个HTTP的头信息Referer,当浏览器向web服务器发送请求的时候,一般都会带上Referer,来告诉浏览器该网页是从哪个页面链接过来的。

后台服务器可以根据获取到的这个Referer信息来判断是否为自己信任的网站地址,如果是则放行继续访问,如果不是则可以返回403(服务端拒绝访问)的状态信息。

在本地模拟上述的服务器效果:

Nginx防盗链的具体实现:

valid_referers:nginx会通就过查看referer自动和valid_referers后面的内容进行匹配,如果匹配到了就将$invalid_referer变量置0,如果没有匹配到,则将$invalid_referer变量置为1,匹配的过程中不区分大小写。

语法 valid_referers none|blocked|server_names|string…
默认值
位置 server、location
  • valid_referers none | blocked | server_names | string ...;

    • none:表示允许没有Referer字段的HTTP请求访问。
    • blocked:表示在Header中的Referer不为空,但是该值被防火墙或代理进行伪装过,如不带 httphttps等协议头的资源允许访问。
    • server_names:资源的白名单,这里可以指定允许访问的域名。
    • string:可自定义字符串,支配通配符、正则表达式写法。如果是正则表达式,需要以~开头表示
location ~*\.(png|jpg|gif){
    valid_referers none blocked www.baidu.com 192.168.200.222 *.example.com example.*  www.example.org  ~\.google\.;
    if ($invalid_referer){
        return 403;
    }
    root /usr/local/nginx/html;

}

遇到的问题:图片有很多,该如何批量进行防盗链?

针对目录进行防盗链

配置如下:

location /images {
    valid_referers none blocked www.baidu.com 192.168.200.222 *.example.com example.*  www.example.org  ~\.google\.;
    if ($invalid_referer){
        return 403;
    }
    root /usr/local/nginx/html;

}

这样我们可以对一个目录下的所有资源进行翻到了操作。

遇到的问题:Referer的限制比较粗,比如随意加一个Referer,上面的方式是无法进行限制的。那么这个问题改如何解决?

此处我们需要用到Nginx的第三方模块ngx_http_accesskey_module,第三方模块如何实现盗链,如果在Nginx中使用第三方模块的功能,这些我们在后面的Nginx的模块篇再进行详细的讲解。

六、Rewirte地址重写

Rewrite是Nginx服务器提供的一个重要基本功能,是Web服务器产品中几乎必备的功能。主要的作用是用来实现URL的重写。

注意:Nginx服务器的Rewrite功能的实现依赖于PCRE的支持,因此在编译安装Nginx服务器之前,需要安装PCRE库。Nginx使用的是ngx_http_rewrite_module模块来解析和处理Rewrite功能的相关配置。

“地址重写”与”地址转发”区别

  • 地址重写浏览器地址会发生变化而地址转发则不变
  • 一次地址重写会产生两次请求而一次地址转发只会产生一次请求
  • 地址重写到的页面必须是一个完整的路径而地址转发则不需要
  • 地址重写因为是两次请求所以request范围内属性不能传递给新页面而地址转发因为是一次请求所以可以传递值
  • 地址转发速度快于地址重写

1、指令

set(设置变量)

该指令用来设置一个新的变量。

语法 set $variable value;
默认值
位置 server、location、if

variable:变量的名称,该变量名称要用”$”作为变量的第一个字符,且不能与Nginx服务器预设的全局变量同名。

value:变量的值,可以是字符串、其他变量或者变量的组合等。

server{
        listen 8080;
        server_name localhost;

        default_type text/plain;

        location /set {
            #设置变量
            set $username 'rewind';

            # if后面必须有一个空格,判断变量是否为空
            if ($username){
                return 200 $username;
            }
            return 200 $remote_addr;
        }
}

Rewrite常用全局变量

变量 说明
$args 变量中存放了请求URL中的请求指令。比如http://192.168.200.133:8080?arg1=value1&args2=value2中的"arg1=value1&arg2=value2",功能和$query_string一样
$http_user_agent 变量存储的是用户访问服务的代理信息(如果通过浏览器访问,记录的是浏览器的相关版本信息)
$host 变量存储的是访问服务器的server_name值
$document_uri 变量存储的是当前访问地址的URI。比如http://192.168.200.133/server?id=10&name=zhangsan中的"/server",功能和$uri一样
$document_root 变量存储的是当前请求对应location的root值,如果未设置,默认指向Nginx自带html目录所在位置
$content_length 变量存储的是请求头中的Content-Length的值
$content_type 变量存储的是请求头中的Content-Type的值
$http_cookie 变量存储的是客户端的cookie信息,可以通过add_header Set-Cookie ‘cookieName=cookieValue’来添加cookie数据
$limit_rate 变量中存储的是Nginx服务器对网络连接速率的限制,也就是Nginx配置中对limit_rate指令设置的值,默认是0,不限制。
$remote_addr 变量中存储的是客户端的IP地址
$remote_port 变量中存储了客户端与服务端建立连接的端口号
$remote_user 变量中存储了客户端的用户名,需要有认证模块才能获取
$scheme 变量中存储了访问协议
$server_addr 变量中存储了服务端的地址
$server_name 变量中存储了客户端请求到达的服务器的名称
$server_port 变量中存储了客户端请求到达服务器的端口号
$server_protocol 变量中存储了客户端请求协议的版本,比如”HTTP/1.1”
$request_body_file 变量中存储了发给后端服务器的本地文件资源的名称
$request_method 变量中存储了客户端的请求方式,比如”GET”,”POST”等
$request_filename 变量中存储了当前请求的资源文件的路径名
$request_uri 变量中存储了当前请求的URI,并且携带请求参数,比如http://192.168.200.133/server?id=10&name=zhangsan中的"/server?id=10&name=zhangsan"

上述参数还可以在日志文件中使用,这个就要用到前面我们介绍的log_format指令

log_format main '$remote_addr - $request - $status-$request_uri  $http_user_agent';

access_log logs/access.log main;

if(判断)

该指令用来支持条件判断,并根据条件判断结果选择不同的Nginx配置。

语法 if (condition){…}
默认值
位置 server、location

condition为判定条件,可以支持以下写法:

  1. 变量名。如果变量名对应的值为空或者是0,if都判断为false,其他条件为true。
if ($param){

}
2. 使用"="和"!="比较变量和字符串是否相等,满足条件为true,不满足为false
if ($request_method = POST){
    return 405;
}

注意:此处和Java不太一样的地方是字符串不需要添加引号

  1. 使用正则表达式对变量进行匹配,匹配成功返回true,否则返回false。变量与正则表达式之间使用”“,”“,”!“,”!\“来连接。

    “~”代表匹配正则表达式过程中区分大小写,

    “~*“代表匹配正则表达式过程中不区分大小写

    “!“和”!*“刚好和上面取相反值,如果匹配上返回false,匹配不上返回true

if ($http_user_agent ~ MSIE){
    #$http_user_agent的值中是否包含MSIE字符串,如果包含返回true
}

注意:正则表达式字符串一般不需要加引号,但是如果字符串中包含”}”或者是”;”等字符时,就需要把引号加上。

  1. 判断请求的文件是否存在使用”-f”和”!-f”,

    当使用”-f”时,如果请求的文件存在返回true,不存在返回false。

    当使用”!f”时,如果请求文件不存在,但该文件所在目录存在返回true,文件和目录都不存在返回false,如果文件存在返回false

if (-f $request_filename){
    #判断请求的文件是否存在
}
if (!-f $request_filename){
    #判断请求的文件是否不存在
}
  1. 判断请求的目录是否存在使用”-d”和”!-d”,

    当使用”-d”时,如果请求的目录存在,if返回true,如果目录不存在则返回false

    当使用”!-d”时,如果请求的目录不存在但该目录的上级目录存在则返回true,该目录和它上级目录都不存在则返回false,如果请求目录存在也返回false.

  2. 判断请求的目录或者文件是否存在使用”-e”和”!-e”

    当使用”-e”,如果请求的目录或者文件存在时,if返回true,否则返回false.

    当使用”!-e”,如果请求的文件和文件所在路径上的目录都不存在返回true,否则返回false

  3. 判断请求的文件是否可执行使用”-x”和”!-x”

    当使用”-x”,如果请求的文件可执行,if返回true,否则返回false

    当使用”!-x”,如果请求文件不可执行,返回true,否则返回false

break指令

该指令用于中断当前相同作用域中的其他Nginx配置。与该指令处于同一作用域的Nginx配置中,位于它前面的指令配置生效,位于后面的指令配置无效。

语法 break;
默认值
位置 server、location、if

例子:

location /{
    if ($param){
        set $id $1;
        break;
        limit_rate 10k;
    }
}

return指令

该指令用于完成对请求的处理,直接向客户端返回响应状态代码。在return后的所有Nginx配置都是无效的。

语法 return code [text];
return code URL;
return URL;
默认值
位置 server、location、if

code:为返回给客户端的HTTP状态代理。可以返回的状态代码为0~999的任意HTTP状态代理

text:为返回给客户端的响应体内容,支持变量的使用

URL:为返回给客户端的URL地址

location /testreturn {

    return 200 success;
}

location /testreturn {

    return https://www.baidu.com; // 302重定向到百度
}

location /testreturn {
    return 302 https://www.baidu.com;
}

location /testreturn {
    return 302 www.baidu.com;//不允许这么写
}

rewrite指令

该指令通过正则表达式的使用来改变URI。可以同时存在一个或者多个指令,按照顺序依次对URL进行匹配和处理。

URL和URI的区别:

URI:统一资源标识符
URL:统一资源定位符
语法 rewrite regex replacement [flag];
默认值
位置 server、location、if

regex:用来匹配URI的正则表达式

replacement:匹配成功后,用于替换URI中被截取内容的字符串。如果该字符串是以”http://“或者”https://“开头的,则不会继续向下对URI进行其他处理,而是直接返回重写后的URI给客户端。

location rewrite {
    rewrite ^/rewrite/url\w*$ https://www.baidu.com;
    rewrite ^/rewrite/(test)\w*$ /$1;
    rewrite ^/rewrite/(demo)\w*$ /$1;
}
location /test{
    default_type text/plain;
    return 200 test_success;
}
location /demo{
    default_type text/plain;
    return 200 demo_success;
}

flag:用来设置rewrite对URI的处理行为,可选值有如下:

  • last:
  • break
  • redirect
  • permanent
last

终止继续在本location块中处理接收到的URI,并将此处重写的URI作为一个新的URI,使用各location块进行处理。该标志将重写后的URI重写在server块中执行,为重写后的URI提供了转入到其他location块的机会。

location /rewrite {
    rewrite ^/rewrite/(test)\w*$ /$1 last;
    rewrite ^/rewrite/(demo)\w*$ /$1 last;
}
location /test{
    default_type text/plain;
    return 200 test_success;
}
location /demo{
    default_type text/plain;
    return 200 demo_success;
}

访问 /rewrite/testabc 时,会先进入第一个location块,之后由第一个rewrite接收并重写地址。last的作用是将重写后的URI重写在当前server块中执行,会被第二个location捕获,并在返回状态码200和字符串test_success。

break

将此处重写的URI作为一个新的URI,在本块中继续进行处理。该标志将重写后的地址在当前的location块中执行,不会将新的URI转向其他的location块。

location rewrite {
    #/test   /usr/local/nginx/html/test/index.html
    rewrite ^/rewrite/(test)\w*$ /$1 break;
    rewrite ^/rewrite/(demo)\w*$ /$1 break;
}
location /test{
    default_type text/plain;
    return 200 test_success;
}
location /demo{
    default_type text/plain;
    return 200 demo_success;
}

访问 http://192.168.200.133:8081/rewrite/demoabc,页面报404错误

redirect

将重写后的URI返回给客户端,状态码为302,指明是临时重定向URI,主要用在replacement变量不是以”http://“或者”https://“开头的情况。

location rewrite {
    rewrite ^/rewrite/(test)\w*$ /$1 redirect;
    rewrite ^/rewrite/(demo)\w*$ /$1 redirect;
}
location /test{
    default_type text/plain;
    return 200 test_success;
}
location /demo{
    default_type text/plain;
    return 200 demo_success;
}

访问http://192.168.200.133:8081/rewrite/testabc请求会被临时重定向,浏览器地址也会发生改变

``http://192.168.200.133:8081/test`

permanent

将重写后的URI返回给客户端,状态码为301,指明是永久重定向URI,主要用在replacement变量不是以”http://“或者”https://“开头的情况。

location rewrite {
    rewrite ^/rewrite/(test)\w*$ /$1 permanent;
    rewrite ^/rewrite/(demo)\w*$ /$1 permanent;
}
location /test{
    default_type text/plain;
    return 200 test_success;
}
location /demo{
    default_type text/plain;
    return 200 demo_success;
}

访问http://192.168.200.133:8081/rewrite/testabc请求会被永久重定向,浏览器地址也会发生改变

rewrite_log指令

该指令配置是否开启URL重写日志的输出功能。

语法 rewrite_log on|off;
默认值 rewrite_log off;
位置 http、server、location、if

开启后,URL重写的相关日志将以notice级别输出到error_log指令配置的日志文件汇总。

rewrite_log on;
error_log  logs/error.log notice;

2、案例

(1)域名跳转

通过Rewrite完成将www.360buy.com的请求跳转到www.jd.com

server {
    listen 80;
    server_name www.360buy.com;
    rewrite ^/ http://www.jd.com permanent;
}

如何在域名跳转的过程中携带请求的URI?

server {
    listen 80;
    server_name www.itheima.com;
    rewrite ^(.*) http://www.hm.com$1 permanent;
}

我们除了上述说的www.jd.comwww.360buy.com其实还有我们也可以通过www.jingdong.com来访问,那么如何通过Rewrite来实现多个域名的跳转?

server{
    listen 80;
    server_name www.360buy.com www.jingdong.com;
    rewrite ^(.*) http://www.jd.com$1 permanent;
}

(2)域名镜像

镜像网站指定是将一个完全相同的网站分别放置到几台服务器上,并分别使用独立的URL进行访问。其中一台服务器上的网站叫主站,其他的为镜像网站。镜像网站和主站没有太大的区别,可以把镜像网站理解为主站的一个备份节点。可以通过镜像网站提供网站在不同地区的响应速度。镜像网站可以平衡网站的流量负载、可以解决网络宽带限制、封锁等。

而我们所说的域名镜像和网站镜像比较类似,上述案例中,将www.itheima.com和 www.itheima.cn都能跳转到www.itcast.cn,那么www.itcast.cn我们就可以把它起名叫主域名,其他两个就是我们所说的镜像域名,当然如果我们不想把整个网站做镜像,只想为其中某一个子目录下的资源做镜像,我们可以在location块中配置rewrite功能,比如:

server {
    listen          80;
    server_name     www.itheima.cn www.itheima.com;
    location /user {
        rewrite ^/user(.*)$ http://www.itcast.cn$1;
    }
    location /emp{
        default_type text/html;
        return 200 '<h1>emp_success</h1>';
    }
}

(3)独立域名

一个完整的项目包含多个模块,比如购物网站有商品搜索模块、商品详情模块和购物车模块等,那么我们如何为每一个模块设置独立的域名。

http://search.itcast.com:81  访问商品搜索模块
http://item.itcast.com:82      访问商品详情模块
http://cart.itcast.com:83      访问商品购物车模块
server{
    listen 81;
    server_name search.itcast.com;
    rewrite ^(.*) http://www.itcast.cn/search$1;
}
server{
    listen 82;
    server_name item.itcast.com;
    rewrite ^(.*) http://www.itcast.cn/item$1;
}
server{
    listen 83;
    server_name cart.itcast.com;
    rewrite ^(.*) http://www.itcast.cn/cart$1;
}

(4)目录自动添加”/“

server {
    listen    8082;
    server_name localhost;
    location /heima {
        root html;
        index index.html;
    }
}

通过http://192.168.200.133:8082/heima和通过http://192.168.200.133:8082/heima/访问的区别?

如果不加斜杠,Nginx服务器内部会自动做一个301的重定向,重定向的地址会有一个指令叫server_name_in_redirect on|off;来决定重定向的地址:

如果该指令为on
    重定向的地址为:  http://server_name:8082/目录名/;
    http://localhost:8082/heima/
如果该指令为off
    重定向的地址为:  http://原URL中的域名:8082/目录名/;
    http://192.168.200.133:8082/heima/

所以就拿刚才的地址来说,http://192.168.200.133:8082/heima如果不加斜杠,那么按照上述规则,如果指令server_name_in_redirect为on,则301重定向地址变为 http://localhost:8082/heima/,如果为off,则301重定向地址变为http://192.168.200.133:8082/heima/。后面这个是正常的,前面地址就有问题。

注意server_name_in_redirect指令在Nginx的0.8.48版本之前默认都是on,之后改成了off,所以现在我们这个版本不需要考虑这个问题,但是如果是0.8.48以前的版本并且server_name_in_redirect设置为on,我们如何通过rewrite来解决这个问题?

我们可以使用rewrite功能为末尾没有斜杠的URL自动添加一个斜杠

server {
    listen    80;
    server_name localhost;
    server_name_in_redirect on;
    location /heima {
        if (-d $request_filename){
            rewrite ^/(.*)([^/])$ http://$host/$1$2/ permanent;
        }
    }
}

(5)合并目录

搜索引擎优化(SEO)是一种利用搜索引擎的搜索规则来提高目的网站在有关搜索引擎内排名的方式。我们在创建自己的站点时,可以通过很多中方式来有效的提供搜索引擎优化的程度。其中有一项就包含URL的目录层级一般不要超过三层,否则的话不利于搜索引擎的搜索也给客户端的输入带来了负担,但是将所有的文件放在一个目录下又会导致文件资源管理混乱并且访问文件的速度也会随着文件增多而慢下来,这两个问题是相互矛盾的,那么使用rewrite如何解决上述问题?

举例,网站中有一个资源文件的访问路径时 /server/11/22/33/44/20.html,也就是说20.html存在于第5级目录下,如果想要访问该资源文件,客户端的URL地址就要写成 http://192.168.200.133/server/11/22/33/44/20.html,

server {
    listen 8083;
    server_name localhost;
    location /server{
        root html;
    }
}

但是这个是非常不利于SEO搜索引擎优化的,同时客户端也不好记.使用rewrite我们可以进行如下配置:

server {
    listen 8083;
    server_name localhost;
    location /server{
        rewrite ^/server-([0-9]+)-([0-9]+)-([0-9]+)-([0-9]+)\.html$ /server/$1/$2/$3/$4/$5.html last;
    }
}

这样的花,客户端只需要输入http://www.web.name/server-11-22-33-44-20.html就可以访问到20.html页面了。这里也充分利用了rewrite指令支持正则表达式的特性。

(6)防盗链

防盗链之前我们已经介绍过了相关的知识,在rewrite中的防盗链和之前将的原理其实都是一样的,只不过通过rewrite可以将防盗链的功能进行完善下,当出现防盗链的情况,我们可以使用rewrite将请求转发到自定义的一张图片和页面,给用户比较好的提示信息。下面我们就通过根据文件类型实现防盗链的一个配置实例:

location /images {
    root html;
    valid_referers none blocked www.baidu.com;
    if ($invalid_referer){
        #return 403;
        rewrite ^/    /images/forbidden.png break;
    }
}

七、黑、白名单

有时候往往有些需求,可能某些接口只能开放给对应的合作商,或者购买/接入API的合作伙伴,那么此时就需要实现类似于IP白名单的功能。而有时候有些恶意攻击者或爬虫程序,被识别后需要禁止其再次访问网站,因此也需要实现IP黑名单。那么这些功能无需交由后端实现,可直接在Nginx中处理。

Nginx做黑白名单机制,主要是通过allow、deny配置项来实现:

allow xxx.xxx.xxx.xxx; # 允许指定的IP访问,可以用于实现白名单。
deny xxx.xxx.xxx.xxx; # 禁止指定的IP访问,可以用于实现黑名单。

要同时屏蔽/开放多个IP访问时,如果所有IP全部写在nginx.conf文件中定然是不显示的,这种方式比较冗余,那么可以新建两个文件BlocksIP.conf、WhiteIP.conf

# --------黑名单:BlocksIP.conf---------
deny 192.177.12.222; # 屏蔽192.177.12.222访问
deny 192.177.44.201; # 屏蔽192.177.44.201访问
deny 127.0.0.0/8; # 屏蔽127.0.0.1到127.255.255.254网段中的所有IP访问
# --------白名单:WhiteIP.conf---------
allow 192.177.12.222; # 允许192.177.12.222访问
allow 192.177.44.201; # 允许192.177.44.201访问
allow 127.45.0.0/16; # 允许127.45.0.1到127.45.255.254网段中的所有IP访问
deny all; # 除开上述IP外,其他IP全部禁止访问

分别将要禁止/开放的IP添加到对应的文件后,可以再将这两个文件在nginx.conf中导入:

http{
    # 屏蔽该文件中的所有IP
    include /soft/nginx/IP/BlocksIP.conf; 
    server{
        location xxx {
            # 某一系列接口只开放给白名单中的IP
            include /soft/nginx/IP/blockip.conf; 
        }
    }
}

对于文件具体在哪儿导入,这个也并非随意的,如果要整站屏蔽/开放就在http中导入,如果只需要一个域名下屏蔽/开放就在sever中导入,如果只需要针对于某一系列接口屏蔽/开放IP,那么就在location中导入。

当然,上述只是最简单的IP黑/白名单实现方式,同时也可以通过ngx_http_geo_module、ngx_http_geo_module第三方库去实现(这种方式可以按地区、国家进行屏蔽,并且提供了IP库)。

八、location匹配规则

符号 说明 优先级
~ 执行一个正则匹配,区分大小写 找到相应匹配则停止匹配其他location,正则匹配按照配置文件中的位置先后匹配
~* 执行一个正则匹配,不区分大小写 找到相应匹配则停止匹配其他location,正则匹配按照配置文件中的位置先后匹配
^~ 普通字符匹配,不是正则匹配。如果该选项匹配,只匹配该选项,不匹配别的选项,一般用来匹配目录 有匹配项,则不再继续匹配其他location
= 普通字符精准匹配 精准匹配会第一个被处理,若有匹配项,则不再继续匹配其他location

先匹配精准匹配(=)及普通字符精准匹配(^),精准匹配(=)及普通字符精准匹配(^)都是匹配到最长符合要求的请求。

正则表达式的匹配(~ and ~*)按照其在配置文件中的位置来,如果正则表达式出现第一个匹配,则不再继续其他正则的匹配,如果没有匹配项,则使用早先记录的,前缀匹配(也就是普通字符匹配)符合的结果。

九、扩展模块

1、sub_filter

sub_filter模块为nginx官方自带的模块,功能为替换掉返回给客户端数据的指定内容。需要使用该功能时只需要在编译时添加对该模块的支持,便会编译到nginx的内核。但是sub_filter的缺点之一是只支持配置一个 sub_filter 替换。

sub_filter 语法包括:

  • sub_filter_types:*; 需要替换的类型,如 text/htmltext/plainapplication/ javascript等,以空格分隔

  • sub_filter_once: on/off; 是否只替换一次

  • sub_filter: xxx1 xxx2; 前面的参数为原始内容,后面的参数为替换后的内容

示例:将 xml 文件中http://ip/tms/services/TMSWebService替换为 http://ip/rest/tms/services/TMSWebService

location /rest/tms/services {
    sub_filter 'http://ip/tms/services/TMSWebService' 'http://ip/rest/tms/services/TMSWebService';
    sub_filter_types text/xml;
    sub_filter_once off;

    proxy_set_header Host $host;
    proxy_set_header   X-Real-IP        $remote_addr;
    proxy_set_header X-Forwarded-For    $remote_addr;
    proxy_pass http://127.0.0.1:8083/tms/services;
}

存在问题

1、跨域问题

浏览器的同源策略:是一种约定,是浏览器最核心也是最基本的安全功能,如果浏览器少了同源策略,则浏览器的正常功能可能都会受到影响。

同源: 协议、域名(IP)、端口相同即为同源

解决方式:使用add_header指令,该指令可以用来添加一些头信息

语法 add_header name value…
默认值
位置 http、server、location

此处用来解决跨域问题,需要添加两个头信息,一个是Access-Control-Allow-Origin,Access-Control-Allow-Methods

Access-Control-Allow-Origin: 直译过来是允许跨域访问的源地址信息,可以配置多个(多个用逗号分隔),也可以使用*代表所有源

Access-Control-Allow-Methods:直译过来是允许跨域访问的请求方式,值可以为 GET POST PUT DELETE…,可以全部设置,也可以根据需要设置,多个用逗号分隔

具体配置方式

location / {
    # 允许跨域的请求,可以自定义变量$http_origin,*表示所有
    add_header 'Access-Control-Allow-Origin' *;
    # 允许携带cookie请求
    add_header 'Access-Control-Allow-Credentials' 'true';
    # 允许跨域请求的方法:GET,POST,OPTIONS,PUT
    add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,PUT';
    # 允许请求时携带的头部信息,*表示所有
    add_header 'Access-Control-Allow-Headers' *;
    # 允许发送按段获取资源的请求
    add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
    # 一定要有!!!否则Post请求无法进行跨域!
    # 在发送Post跨域请求前,会以Options方式发送预检请求,服务器接受时才会正式请求
    if ($request_method = 'OPTIONS') {
        add_header 'Access-Control-Max-Age' 1728000;
        add_header 'Content-Type' 'text/plain; charset=utf-8';
        add_header 'Content-Length' 0;
        # 对于Options方式的请求返回204,表示接受跨域请求
        return 204;
    }
}

2、nginx代理后无法获取token

原因:NGINX对header有所限制,下划线(_)不支持

解决方式1:请求头参数不用带下划线参数

解决方式2:在 nginx.conf 的配置文件 http 代码块下添加以下代码

underscores_in_headers on;

(默认 underscores_in_headers 为off)

常用命令总结

1、在location 中 echo “hello Nginx!” 访问可以直接输出文字

location / {
    echo "hello Nginx!"
}

2、location匹配规则:

1)最低级别匹配规则:
location / {
    echo "hello Nginx!"
}
2)最高级别匹配规则:
location /user {
    echo "hello user.hmtl"
}
3)其它级别匹配规则:
location ^~ /user {
    echo "hello user.hmtl"
}
location ~^ /user {
    echo "hello user.hmtl"
}
location ~ ^/[a-z] {
    echo "hello user.hmtl"
}
location ~ ^/\a {
    echo "hello user.hmtl"
}

3、反向代理细节:

location /user {
    proxy_pass http://ip;
}
location /order/ {
    proxy_pass http://ip/;
}
访问结果:
http://ip/user/xx...
http://ip/xx...

4、负载均衡配置

upstream order {
    server 192.168.5.18:8080 weight=1;
    server 192.168.5.18:8081 weight=1;
}
server{
    location /order/ {
        proxy_pass http://order/;
    }
}
注:weight=1,配置的为权重,值越高权重越高

  目录