乐趣区

关于nginx:Nginx前端入门

Nginx 介绍

传统的 Web 服务器,每个客户端连贯作为一个独自的过程或线程解决,需在切换工作时将 CPU 切换到新的工作并创立一个新的运行时上下文,耗费额定的内存和 CPU 工夫,当并发申请减少时,服务器响应变慢,从而对性能产生负面影响。


Nginx 是开源、高性能、高牢靠的 Web 和反向代理服务器,而且反对热部署,简直能够做到 7 * 24 小时不间断运行,即便运行几个月也不须要重新启动,还能在不间断服务的状况下对软件版本进行热更新。性能是 Nginx 最重要的考量,其占用内存少、并发能力强、能反对高达 5w 个并发连接数,最重要的是,Nginx 是收费的并能够商业化,配置应用也比较简单。

Nginx 的最重要的几个应用场景:

  1. 动态资源服务,通过本地文件系统提供服务;
  2. 反向代理服务,延长出包含缓存、负载平衡等;
  3. API 服务,OpenResty;

对于前端来说 Node.js 不生疏了,Nginx 和 Node.js 的很多理念相似,HTTP 服务器、事件驱动、异步非阻塞等,且 Nginx 的大部分性能应用 Node.js 也能够实现,但 Nginx 和 Node.js 并不抵触,都有本人善于的畛域。Nginx 擅长于底层服务器端资源的解决(动态资源解决转发、反向代理,负载平衡等),Node.js 更善于下层具体业务逻辑的解决,两者能够完满组合,独特助力前端开发。

上面咱们着重学习一下 Nginx 的应用。

相干概念

2.1 简略申请和非简略申请

首先咱们来理解一下简略申请和非简略申请,如果同时满足上面两个条件,就属于简略申请:

  1. 申请办法是 HEAD、GET、POST 三种之一;
  2. HTTP 头信息不超过左边着几个字段:Accept、Accept-Language、Content-Language、Last-Event-IDContent-Type 只限于三个值 application/x-www-form-urlencoded、multipart/form-data、text/plain;

但凡不同时满足这两个条件的,都属于非简略申请。

浏览器解决简略申请和非简略申请的形式不一样:

简略申请

对于简略申请,浏览器会在头信息中减少 Origin 字段后间接收回,Origin 字段用来阐明,本次申请来自的哪个源(协定 + 域名 + 端口)。

如果服务器发现 Origin 指定的源不在许可范畴内,服务器会返回一个失常的 HTTP 回应,浏览器取到回应之后发现回应的头信息中没有蕴含 Access-Control-Allow-Origin 字段,就抛出一个谬误给 XHR 的 error 事件;

如果服务器发现 Origin 指定的域名在许可范畴内,服务器返回的响应会多出几个 Access-Control- 结尾的头信息字段。

非简略申请

非简略申请是那种对服务器有特殊要求的申请,比方申请办法是 PUT 或 DELETE,或 Content-Type 值为 application/json。浏览器会在正式通信之前,发送一次 HTTP 预检 OPTIONS 申请,先询问服务器,以后网页所在的域名是否在服务器的许可名单之中,以及能够应用哪些 HTTP 申请办法和头信息字段。只有失去必定回答,浏览器才会收回正式的 XHR 申请,否则报错。

2.2 跨域

在浏览器上以后拜访的网站向另一个网站发送申请获取数据的过程就是跨域申请。

跨域是浏览器的同源策略决定的,是一个重要的浏览器安全策略,用于限度一个 origin 的文档或者它加载的脚本与另一个源的资源进行交互,它可能帮忙阻隔歹意文档,缩小可能被攻打的媒介,能够应用 CORS 配置解除这个限度。

对于跨域网上曾经有很多解释,这里就不啰嗦,也能够间接看 MDN 的 < 浏览器的同源策略 > 文档进一步理解,这里就列举几个同源和不同元的例子,置信程序员都能看得懂。

# 同源的例子

http://example.com/app1/index.html  # 只是门路不同
http://example.com/app2/index.html

http://Example.com:80  # 只是大小写差别
http://example.com

# 不同源的例子

http://example.com/app1   # 协定不同
https://example.com/app2

http://example.com        # host 不同
http://www.example.com
http://myapp.example.com

http://example.com        # 端口不同
http://example.com:8080

2.3 正向代理和反向代理

反向代理(Reverse Proxy)对应的是正向代理(Forward Proxy),他们的区别:

正向代理:个别的拜访流程是客户端间接向指标服务器发送申请并获取内容,应用正向代理后,客户端改为向代理服务器发送申请,并指定指标服务器(原始服务器),而后由代理服务器和原始服务器通信,转交申请并取得的内容,再返回给客户端。正向代理暗藏了实在的客户端,为客户端收发申请,使实在客户端对服务器不可见;

举个具体的例子 ????,你的浏览器无奈间接拜访谷哥,这时候能够通过一个代理服务器来帮忙你拜访谷哥,那么这个服务器就叫正向代理。

反向代理:与个别拜访流程相比,应用反向代理后,间接收到申请的服务器是代理服务器,而后将申请转发给外部网络上真正进行解决的服务器,失去的后果返回给客户端。反向代理暗藏了实在的服务器,为服务器收发申请,使实在服务器对客户端不可见。个别在解决跨域申请的时候比拟罕用。当初基本上所有的大型网站都设置了反向代理。

举个具体的例子 ????,去饭店吃饭,能够点川菜、粤菜、江浙菜,饭店也别离有三个菜系的厨师 ????‍????,然而你作为顾客不必管哪个厨师给你做的菜,只用点菜即可,小二将你菜单中的菜调配给不同的厨师来具体解决,那么这个小二就是反向代理服务器。

简略的说,个别给客户端做代理的都是正向代理,给服务器做代理的就是反向代理。

正向代理和反向代理次要的原理区别能够参见下图:

2.4 负载平衡

个别状况下,客户端发送多个申请到服务器,服务器解决申请,其中一部分可能要操作一些资源比方数据库、动态资源等,服务器处理完毕后,再将后果返回给客户端。

这种模式对于晚期的零碎来说,性能要求不简单,且并发申请绝对较少的状况下还能胜任,老本也低。随着信息数量一直增长,访问量和数据量飞速增长,以及零碎业务复杂度继续减少,这种做法已无奈满足要求,并发量特地大时,服务器容易崩。

很显著这是因为服务器性能的瓶颈造成的问题,除了堆机器之外,最重要的做法就是负载平衡。

申请爆发式增长的状况下,单个机器性能再强劲也无奈满足要求了,这个时候集群的概念产生了,单个服务器解决不了的问题,能够应用多个服务器,而后将申请散发到各个服务器上,将负载散发到不同的服务器,这就是负载平衡,外围是「摊派压力」。Nginx 实现负载平衡,一般来说指的是将申请转发给服务器集群。

举个具体的例子 ????,晚顶峰乘坐地铁的时候,入站口常常会有地铁工作人员大喇叭“请走 B 口,B 口人少车空 ….”,这个工作人员的作用就是负载平衡。

2.5 动静拆散

为了放慢网站的解析速度,能够把动静页面和动态页面由不同的服务器来解析,放慢解析速度,升高原来单个服务器的压力。


一般来说,都须要将动静资源和动态资源离开,因为 Nginx 的高并发和动态资源缓存等个性,常常将动态资源部署在 Nginx 上。如果申请的是动态资源,间接到动态资源目录获取资源,如果是动静资源的申请,则利用反向代理的原理,把申请转发给对应后盾利用去解决,从而实现动静拆散。

应用前后端拆散后,能够很大水平晋升动态资源的访问速度,即便动静服务不可用,动态资源的拜访也不会受到影响。

Nginx 疾速装置

3.1 装置

咱们能够先看看

yum list | grep nginx

来看看


而后

yum install nginx

来装置 Nginx,而后咱们在命令行中 nginx -v 就能够看到具体的 Nginx 版本信息,也就装置结束了。

3.2 相干文件夹

而后咱们能够应用 rpm -ql nginx 来查看 Nginx 被装置到了什么中央,有哪些相干目录,其中位于 /etc 目录下的次要是配置文件,还有一些文件见下图:


次要关注的文件夹有两个:

  1. /etc/nginx/conf.d/ 文件夹,是咱们进行子配置的配置项存放处,/etc/nginx/nginx.conf 主配置文件会默认把这个文件夹中所有子配置项都引入;
  2. /usr/share/nginx/html/ 文件夹,通常动态文件都放在这个文件夹,也能够依据你本人的习惯放其余中央;

3.3 跑起来康康

装置之后开启 Nginx,如果零碎开启了防火墙,那么须要设置一下在防火墙中退出须要凋谢的端口,上面列举几个罕用的防火墙操作(没开启的话不必管这个):

systemctl start firewalld  # 开启防火墙
systemctl stop firewalld   # 敞开防火墙
systemctl status firewalld # 查看防火墙开启状态,显示 running 则是正在运行
firewall-cmd --reload      # 重启防火墙,永恒关上端口须要 reload 一下

# 增加开启端口,--permanent 示意永恒关上,不加是长期关上重启之后生效

firewall-cmd --permanent --zone=public --add-port=8888/tcp

# 查看防火墙,增加的端口也能够看到

firewall-cmd --list-all

而后设置 Nginx 的开机启动:

systemctl enable nginx

启动 Nginx(其余命令前面有具体解说):

systemctl start nginx

而后拜访你的 IP,这时候就能够看到 Nginx 的欢送页面了~ Welcome to nginx!????

3.4 装置 nvm & node & git

# 下载 nvm,或者看官网的步骤 https://github.com/nvm-sh/nvm#install--update-script

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.3/install.sh | bash

source   ~/.bashrc    # 装置结束后,更新配置文件即可应用 nvm 命令
nvm ls-remote         # 查看近程 node 版本
nvm install v12.16.3  # 选一个你要装置的版本装置,我这里抉择 12.16.3
nvm list              # 装置结束查看装置的 node 版本
node -v               # 查看是否装置好了

yum install git   # git 装置

Nginx 操作常用命令

Nginx 的命令在控制台中输出 nginx -h 就能够看到残缺的命令,这里列举几个罕用的命令:

nginx -s reload  # 向主过程发送信号,从新加载配置文件,热重启
nginx -s reopen     # 重启 Nginx
nginx -s stop    # 疾速敞开
nginx -s quit    # 期待工作过程解决实现后敞开
nginx -T         # 查看以后 Nginx 最终的配置
nginx -t -c < 配置门路 >    # 查看配置是否有问题,如果曾经在配置目录,则不须要 -c

systemctl 是 Linux 零碎利用管理工具 systemd 的主命令,用于管理系统,咱们也能够用它来对 Nginx 进行治理,相干命令如下:

systemctl start nginx    # 启动 Nginx
systemctl stop nginx     # 进行 Nginx
systemctl restart nginx  # 重启 Nginx
systemctl reload nginx   # 从新加载 Nginx,用于批改配置后
systemctl enable nginx   # 设置开机启动 Nginx
systemctl disable nginx  # 敞开开机启动 Nginx
systemctl status nginx   # 查看 Nginx 运行状态

Nginx 配置语法

就跟后面文件作用解说的图所示,Nginx 的主配置文件是 /etc/nginx/nginx.conf,你能够应用 cat -n nginx.conf 来查看配置。

nginx.conf 结构图能够这样概括:

main # 全局配置,对全局失效
├── events # 配置影响 Nginx 服务器或与用户的网络连接
├── http # 配置代理,缓存,日志定义等绝大多数性能和第三方模块的配置
│ ├── upstream # 配置后端服务器具体地址,负载平衡配置不可或缺的局部
│ ├── server # 配置虚拟主机的相干参数,一个 http 块中能够有多个 server 块
│ ├── server
│ │ ├── location # server 块能够蕴含多个 location 块,location 指令用于匹配 uri
│ │ ├── location
│ │ └── …
│ └── …
└── …
一个 Nginx 配置文件的构造就像 nginx.conf 显示的那样,配置文件的语法规定:

配置文件由指令与指令块形成;

每条指令以 ; 分号结尾,指令与参数间以空格符号分隔;

指令块以 {} 大括号将多条指令组织在一起;

include 语句容许组合多个配置文件以晋升可维护性;

应用 # 符号增加正文,进步可读性;

应用 $ 符号应用变量;

局部指令的参数反对正则表达式;

5.1 典型配置

Nginx 的典型配置:

user  nginx;                        # 运行用户,默认即是 nginx,能够不进行设置
worker_processes  1;                # Nginx 过程数,个别设置为和 CPU 核数一样
error_log  /var/log/nginx/error.log warn;   # Nginx 的谬误日志寄存目录
pid        /var/run/nginx.pid;      # Nginx 服务启动时的 pid 寄存地位
 
events {use epoll;     # 应用 epoll 的 I / O 模型(如果你不晓得 Nginx 该应用哪种轮询办法,会主动抉择一个最适宜你操作系统的)
    worker_connections 1024;   # 每个过程容许最大并发数
}
 
http {   # 配置应用最频繁的局部,代理、缓存、日志定义等绝大多数性能和第三方模块的配置都在这里设置
    # 设置日志模式
    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  /var/log/nginx/access.log  main;   # Nginx 拜访日志寄存地位
 
    sendfile            on;   # 开启高效传输模式
    tcp_nopush          on;   # 缩小网络报文段的数量
    tcp_nodelay         on;
    keepalive_timeout   65;   # 放弃连贯的工夫,也叫超时工夫,单位秒
    types_hash_max_size 2048;
 
    include             /etc/nginx/mime.types;      # 文件扩展名与类型映射表
    default_type        application/octet-stream;   # 默认文件类型
 
    include /etc/nginx/conf.d/*.conf;   # 加载子配置项
    
    server {
        listen       80;       # 配置监听的端口
        server_name  localhost;    # 配置的域名
        
        location / {
            root   /usr/share/nginx/html;  # 网站根目录
            index  index.html index.htm;   # 默认首页文件
            deny 172.168.22.11;   # 禁止拜访的 ip 地址,能够为 all
            allow 172.168.33.44;# 容许拜访的 ip 地址,能够为 all
        }
        
        error_page 500 502 503 504 /50x.html;  # 默认 50x 对应的拜访页面
        error_page 400 404 error.html;   # 同上
    }
}

server 块能够蕴含多个 location 块,location 指令用于匹配 uri,语法:

location [= | ~ | ~* | ^~] uri {...}

指令前面:

= 准确匹配门路,用于不含正则表达式的 uri 前,如果匹配胜利,不再进行后续的查找;

^~ 用于不含正则表达式的 uri 前,示意如果该符号前面的字符是最佳匹配,采纳该规定,不再进行后续的查找;

~ 示意用该符号前面的正则去匹配门路,辨别大小写;

~* 示意用该符号前面的正则去匹配门路,不辨别大小写。跟 ~ 优先级都比拟低,如有多个 location 的正则能匹配的话,则应用正则表达式最长的那个;

如果 uri 蕴含正则表达式,则必须要有 ~ 或 ~* 标记。

5.2 全局变量

Nginx 有一些罕用的全局变量,你能够在配置的任何地位应用它们,如下表:

全局变量名 性能
$host 申请信息中的 Host,如果申请中没有 Host 行,则等于设置的服务器名,不蕴含端口
$request_method 客户端申请类型,如 GETPOST
$remote_addr 客户端的 IP 地址
$args 申请中的参数
$arg_PARAMETER GET 申请中变量名 PARAMETER 参数的值,例如:$http_user_agent(Uaer-Agent 值), $http_referer
$content_length 申请头中的 Content-length 字段
$http_user_agent 客户端 agent 信息
$http_cookie 客户端 cookie 信息
$remote_addr 客户端的 IP 地址
$remote_port 客户端的端口
$http_user_agent 客户端 agent 信息
$server_protocol 申请应用的协定,如 HTTP/1.0HTTP/1.1
$server_addr 服务器地址
$server_name 服务器名称
$server_port 服务器的端口号
$scheme HTTP 办法(如 http,https)

还有更多的内置预约义变量,能够间接搜寻关键字「nginx 内置预约义变量」能够看到一堆博客写这个,这些变量都能够在配置文件中间接应用。

设置二级域名虚拟主机

在某某云 ☁️ 上购买了域名之后,就能够配置虚拟主机了,个别配置的门路在 域名治理 -> 解析 -> 增加记录 中增加二级域名,配置后某某云会把二级域名也解析到咱们配置的服务器 IP 上,而后咱们在 Nginx 上配置一下虚拟主机的拜访监听,就能够拿到从这个二级域名过去的申请了。

当初我本人的服务器上配置了一个 fe 的二级域名,也就是说在外网拜访 fe.sherlocked93.club 的时候,也能够拜访到咱们的服务器了。

因为默认配置文件 /etc/nginx/nginx.conf 的 http 模块中有一句 include /etc/nginx/conf.d/.conf 也就是说 conf.d 文件夹下的所有 .conf 文件都会作为子配置项被引入配置文件中。为了保护不便,我在 /etc/nginx/conf.d 文件夹中新建一个 fe.sherlocked93.club.conf:

# /etc/nginx/conf.d/fe.sherlocked93.club.conf

server {
  listen 80;
    server_name fe.sherlocked93.club;

    location / {
        root  /usr/share/nginx/html/fe;
        index index.html;
    }

}

而后在 /usr/share/nginx/html 文件夹下新建 fe 文件夹,新建文件 index.html,内容轻易写点,改完 nginx -s reload 从新加载,浏览器中输出 fe.sherlocked93.club,发现从二级域名就能够拜访到咱们刚刚新建的 fe 文件夹:

配置反向代理

反向代理是工作中最罕用的服务器性能,常常被用来解决跨域问题,上面简略介绍一下如何实现反向代理。4

反向代理是工作中最罕用的服务器性能,常常被用来解决跨域问题,上面简略介绍一下如何实现反向代理。

首先进入 Nginx 的主配置文件:

vim /etc/nginx/nginx.conf

为了看起来不便,把行号显示进去 :set nu(集体习惯),而后咱们去 http 模块的 server 块中的 location /,减少一行将默认网址重定向到最大学习网站 Bilibili 的 proxy_pass 配置 ????:

改完保留退出,nginx -s reload 从新加载,进入默认网址,那么当初就间接跳转到 B 站了,实现了一个简略的代理。

理论应用中,能够将申请转发到本机另一个服务器上,也能够依据拜访的门路跳转到不同端口的服务中。

比方咱们监听 9001 端口,而后把拜访不同门路的申请进行反向代理:

  1. 把拜访 http://127.0.0.1:9001/edu 的申请转发到 http://127.0.0.1:8080
  2. 把拜访 http://127.0.0.1:9001/vod 的申请转发到 http://127.0.0.1:8081

这种要怎么配置呢,首先同样关上主配置文件,而后在 http 模块下减少一个 server 块:

server {
  listen 9001;
  server_name *.sherlocked93.club;
 
  location ~ /edu/ {proxy_pass http://127.0.0.1:8080;}
  
  location ~ /vod/ {proxy_pass http://127.0.0.1:8081;}
}

反向代理还有一些其余的指令,能够理解一下:

  1. proxy_set_header:在将客户端申请发送给后端服务器之前,更改来自客户端的申请头信息;
  2. proxy_connect_timeout:配置 Nginx 与后端代理服务器尝试建设连贯的超时工夫;
  3. proxy_read_timeout:配置 Nginx 向后端服务器组收回 read 申请后,期待相应的超时工夫;
  4. proxy_send_timeout:配置 Nginx 向后端服务器组收回 write 申请后,期待相应的超时工夫;
  5. proxy_redirect:用于批改后端服务器返回的响应头中的 Location 和 Refresh。

跨域 CORS 配置

对于简略申请、非简略申请、跨域的概念,后面曾经介绍过了,还不理解的能够看看后面的解说。当初前后端拆散的我的项目一统天下,常常本地起了前端服务,须要拜访不同的后端地址,不可避免遇到跨域问题。

要解决跨域问题,咱们来制作一个跨域问题。首先和后面设置二级域名的形式一样,先设置好 fe.sherlocked93.club 和 be.sherlocked93.club 二级域名,都指向本云服务器地址,尽管对应 IP 是一样的,然而在 fe.sherlocked93.club 域名收回的申请拜访 be.sherlocked93.club 域名的申请还是跨域了,因为拜访的 host 不统一(如果不晓得啥起因参见后面跨域的内容)。

8.1 应用反向代理解决跨域

在前端服务地址为 fe.sherlocked93.club 的页面申请 be.sherlocked93.club 的后端服务导致的跨域,能够这样配置:

server {
  listen 9001;
  server_name fe.sherlocked93.club;

  location / {proxy_pass be.sherlocked93.club;}
}

这样就将对前一个域名 fe.sherlocked93.club 的申请全都代理到了 be.sherlocked93.club,前端的申请都被咱们用服务器代理到了后端地址下,绕过了跨域。

这里对动态文件的申请和后端服务的申请都以 fe.sherlocked93.club 开始,不易辨别,所以为了实现对后端服务申请的对立转发,通常咱们会约定对后端服务的申请加上 /apis/ 前缀或者其余的 path 来和对动态资源的申请加以辨别,此时咱们能够这样配置:

# 申请跨域,约定代理后端服务申请 path 以 /apis/ 结尾
location ^~/apis/ {
    # 这里重写了申请,将正则匹配中的第一个分组的 path 拼接到真正的申请前面,并用 break 进行后续匹配
    rewrite ^/apis/(.*)$ /$1 break;
    proxy_pass be.sherlocked93.club;
  
    # 两个域名之间 cookie 的传递与回写
    proxy_cookie_domain be.sherlocked93.club fe.sherlocked93.club;
}

这样,动态资源咱们应用 fe.sherlocked93.club/xx.html,动静资源咱们应用 fe.sherlocked93.club/apis/getAwo,浏览器页面看起来依然拜访的前端服务器,绕过了浏览器的同源策略,毕竟咱们看起来并没有跨域。

也能够对立一点,间接把前后端服务器地址间接都转发到另一个 server.sherlocked93.club,只通过在前面增加的 path 来辨别申请的是动态资源还是后端服务,看需要了。

8.2 配置 header 解决跨域

当浏览器在拜访跨源的服务器时,也能够在跨域的服务器上间接设置 Nginx,从而前端就能够无感地开发,不必把实际上拜访后端的地址改成前端服务的地址,这样可适性更高。

比方前端站点是 fe.sherlocked93.club,这个地址下的前端页面申请 be.sherlocked93.club 下的资源,比方前者的 fe.sherlocked93.club/index.html 内容是这样的:

<html>
<body>
    <h1>welcome fe.sherlocked93.club!!<h1>
    <script type='text/javascript'>
    var xmlhttp = new XMLHttpRequest()
    xmlhttp.open("GET", "http://be.sherlocked93.club/index.html", true);
    xmlhttp.send();
    </script>
</body>
</html>

关上浏览器拜访 fe.sherlocked93.club/index.html 的后果如下:

很显著这里是跨域申请,在浏览器中间接拜访 http://be.sherlocked93.club/i… 是能够拜访到的,然而在 fe.sherlocked93.club 的 html 页面拜访就会呈现跨域。

在 /etc/nginx/conf.d/ 文件夹中新建一个配置文件,对应二级域名 be.sherlocked93.club:

# /etc/nginx/conf.d/be.sherlocked93.club.conf
 
server {
  listen       80;
  server_name  be.sherlocked93.club;
  
    add_header 'Access-Control-Allow-Origin' $http_origin;   # 全局变量取得以后申请 origin,带 cookie 的申请不反对 *
    add_header 'Access-Control-Allow-Credentials' 'true';    # 为 true 可带上 cookie
    add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';  # 容许申请办法
    add_header 'Access-Control-Allow-Headers' $http_access_control_request_headers;  # 容许申请的 header,能够为 *
    add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
    
  if ($request_method = 'OPTIONS') {
        add_header 'Access-Control-Max-Age' 1728000;   # OPTIONS 申请的有效期,在有效期内不必收回另一条预检申请
        add_header 'Content-Type' 'text/plain; charset=utf-8';
        add_header 'Content-Length' 0;
    
        return 204;                  # 200 也能够
    }
  
    location / {
        root  /usr/share/nginx/html/be;
        index index.html;
    }
}

而后 nginx -s reload 从新加载配置。这时再拜访 fe.sherlocked93.club/index.html 后果如下,申请中呈现了咱们刚刚配置的 Header:

解决了跨域问题。

开启 gzip 压缩

gzip 是一种罕用的网页压缩技术,传输的网页通过 gzip 压缩之后大小通常能够变为原来的一半甚至更小(官网原话),更小的网页体积也就意味着带宽的节约和传输速度的晋升,特地是对于访问量微小大型网站来说,每一个动态资源体积的减小,都会带来可观的流量与带宽的节俭。

百度能够找到很多检测站点来查看指标网页有没有开启 gzip 压缩,在下轻易找了一个 < 网页 GZIP 压缩检测 > 输出掘金 juejin.im 来偷窥下掘金有没有开启 gzip。

这里能够看到掘金是开启了 gzip 的,压缩成果还挺不错,达到了 52% 之多,原本 34kb 的网页体积,压缩完只须要 16kb,能够设想网页传输速度晋升了不少。

9.1 Nginx 配置 gzip

应用 gzip 不仅须要 Nginx 配置,浏览器端也须要配合,须要在申请音讯头中蕴含 Accept-Encoding: gzip(IE5 之后所有的浏览器都反对了,是古代浏览器的默认设置)。个别在申请 html 和 css 等动态资源的时候,反对的浏览器在 request 申请动态资源的时候,会加上 Accept-Encoding: gzip 这个 header,示意本人反对 gzip 的压缩形式,Nginx 在拿到这个申请的时候,如果有相应配置,就会返回通过 gzip 压缩过的文件给浏览器,并在 response 相应的时候加上 content-encoding: gzip 来通知浏览器本人采纳的压缩形式(因为浏览器在传给服务器的时候个别还通知服务器本人反对好几种压缩形式),浏览器拿到压缩的文件后,依据本人的解压形式进行解析。

先来看看 Nginx 怎么进行 gzip 配置,和之前的配置一样,为了方便管理,还是在 /etc/nginx/conf.d/ 文件夹中新建配置文件 gzip.conf:

# /etc/nginx/conf.d/gzip.conf
 
gzip on; # 默认 off,是否开启 gzip
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
 
# 下面两个开启根本就能跑起了,上面的违心折腾就理解一下
gzip_static on;
gzip_proxied any;
gzip_vary on;
gzip_comp_level 6;
gzip_buffers 16 8k;
# gzip_min_length 1k;
gzip_http_version 1.1;

略微解释一下:

  1. gzip_types:要采纳 gzip 压缩的 MIME 文件类型,其中 text/html 被零碎强制启用;
  2. gzip_static:默认 off,该模块启用后,Nginx 首先查看是否存在申请动态文件的 gz 结尾的文件,如果有则间接返回该 .gz 文件内容;
  3. gzip_proxied:默认 off,nginx 做为反向代理时启用,用于设置启用或禁用从代理服务器上收到相应内容 gzip 压缩;
  4. gzip_vary:用于在响应音讯头中增加 Vary:Accept-Encoding,使代理服务器依据申请头中的 Accept-Encoding 辨认是否启用 gzip 压缩;
  5. gzip_comp_level:gzip 压缩比,压缩级别是 1-9,1 压缩级别最低,9 最高,级别越高压缩率越大,压缩工夫越长,倡议 4-6;
  6. gzip_buffers:获取多少内存用于缓存压缩后果,16 8k 示意以 8k*16 为单位取得;
  7. gzip_min_length:容许压缩的页面最小字节数,页面字节数从 header 头中的 Content-Length 中进行获取。默认值是 0,不论页面多大都压缩。倡议设置成大于 1k 的字节数,小于 1k 可能会越压越大;
  8. gzip_http_version:默认 1.1,启用 gzip 所需的 HTTP 最低版本;

这个配置能够插入到 http 模块整个服务器的配置里,也能够插入到须要应用的虚拟主机的 server 或者上面的 location 模块中,当然像下面咱们这样写的话就是被 include 到 http 模块中了。

其余更全的配置信息能够查看 < 官网文档 ngx_http_gzip_module>,配置前是这样的:

配置之后 response 的 header 外面多了一个 Content-Encoding: gzip,返回信息被压缩了:

留神了,个别 gzip 的配置倡议加上 gzip_min_length 1k,不加的话:

因为文件太小,gzip 压缩之后失去了 -48% 的体积优化,压缩之后体积还比压缩之前体积大了,所以最好设置低于 1kb 的文件就不要 gzip 压缩了 ????

9.2 Webpack 的 gzip 配置

以后端我的项目应用 Webpack 进行打包的时候,也能够开启 gzip 压缩:

// vue-cli3 的 vue.config.js 文件
const CompressionWebpackPlugin = require('compression-webpack-plugin')
 
module.exports = {
  // gzip 配置
  configureWebpack: config => {if (process.env.NODE_ENV === 'production') {
      // 生产环境
      return {
        plugins: [new CompressionWebpackPlugin({
          test: /\.js$|\.html$|\.css/,    // 匹配文件名
          threshold: 10240,               // 文件压缩阈值,对超过 10k 的进行压缩
          deleteOriginalAssets: false     // 是否删除源文件
        })]
      }
    }
  },
  ...
}

由此打包进去的文件如下图:

这里能够看到某些打包之后的文件上面有一个对应的 .gz 通过 gzip 压缩之后的文件,这是因为这个文件超过了 10kb,有的文件没有超过 10kb 就没有进行 gzip 打包,如果你冀望压缩文件的体积阈值小一点,能够在 compression-webpack-plugin 这个插件的配置里进行对应配置。

那么为啥这里 Nginx 曾经有了 gzip 压缩,Webpack 这里又整了个 gzip 呢,因为如果全都是应用 Nginx 来压缩文件,会消耗服务器的计算资源,如果服务器的 gzip_comp_level 配置的比拟高,就更减少服务器的开销,相应减少客户端的申请工夫,得失相当。

如果压缩的动作在前端打包的时候就做了,把打包之后的高压缩等级文件作为动态资源放在服务器上,Nginx 会优先查找这些压缩之后的文件返回给客户端,相当于把压缩文件的动作从 Nginx 提前给 Webpack 打包的时候实现,节约了服务器资源,所以个别推介在生产环境利用 Webpack 配置 gzip 压缩。

配置负载平衡

负载平衡在之前曾经介绍了相干概念了,次要思维就是把负载平均正当地散发到多个服务器上,实现压力分流的目标。

次要配置如下:

http {
  upstream myserver {
      # ip_hash;  # ip_hash 形式
    # fair;   # fair 形式
    server 127.0.0.1:8081;  # 负载平衡目标服务地址
    server 127.0.0.1:8080;
    server 127.0.0.1:8082 weight=10;  # weight 形式,不写默认为 1
  }
 
  server {
    location / {
        proxy_pass http://myserver;
      proxy_connect_timeout 10;
    }
  }
}

Nginx 提供了好几种调配形式,默认为轮询,就是轮流来。有以下几种调配形式:

  • 轮询,默认形式,每个申请按工夫程序逐个调配到不同的后端服务器,如果后端服务挂了,能主动剔除;
  • weight,权重调配,指定轮询几率,权重越高,在被拜访的概率越大,用于后端服务器性能不均的状况;
  • ip_hash,每个申请按拜访 IP 的 hash 后果调配,这样每个访客固定拜访一个后端服务器,能够解决动静网页 session 共享问题。负载平衡每次申请都会从新定位到服务器集群中的某一个,那么曾经登录某一个服务器的用户再从新定位到另一个服务器,其登录信息将会失落,这样显然是不妥的;
  • fair(第三方),按后端服务器的响应工夫调配,响应工夫短的优先调配,依赖第三方插件 nginx-upstream-fair,须要先装置;

配置动静拆散

动静拆散在之前也介绍过了,就是把动静和动态的申请离开。形式次要有两种,一种 是纯正把动态文件独立成独自的域名,放在独立的服务器上,也是目前支流推崇的计划。另外一种办法就是动静跟动态文件混合在一起公布,通过 Nginx 配置来离开。

通过 location 指定不同的后缀名实现不同的申请转发。通过 expires 参数设置,能够使浏览器缓存过期工夫,缩小与服务器之前的申请和流量。具体 expires 定义:是给一个资源设定一个过期工夫,也就是说无需去服务端验证,间接通过浏览器本身确认是否过期即可,所以不会产生额定的流量。此种办法非常适合不常常变动的资源。(如果常常更新的文件,不倡议应用 expires 来缓存),我这里设置 3d,示意在这 3 天之内拜访这个 URL,发送一个申请,比对服务器该文件最初更新工夫没有变动。则不会从服务器抓取,返回状态码 304,如果有批改,则间接从服务器从新下载,返回状态码 200。

server {
  location /www/ {
      root /data/;
    index index.html index.htm;
  }
  
  location /image/ {
      root /data/;
    autoindex on;
  }
}

配置高可用集群(双机热备)

当主 Nginx 服务器宕机之后,切换到备份 Nginx 服务器

首先装置 keepalived,

yum install keepalived -y

而后编辑 /etc/keepalived/keepalived.conf 配置文件,并在配置文件中减少 vrrp_script 定义一个外围检测机制,并在 vrrp_instance 中通过定义 track_script 来追踪脚本执行过程,实现节点转移:

global_defs{
   notification_email {acassen@firewall.loc}
   notification_email_from Alexandre@firewall.loc
   smtp_server 127.0.0.1
   smtp_connect_timeout 30 // 下面都是邮件配置,没卵用
   router_id LVS_DEVEL     // 以后服务器名字,用 hostname 命令来查看
}
vrrp_script chk_maintainace { // 检测机制的脚本名称为 chk_maintainace
    script "[[-e/etc/keepalived/down]] && exit 1 || exit 0" // 能够是脚本门路或脚本命令
    // script "/etc/keepalived/nginx_check.sh"    // 比方这样的脚本门路
    interval 2  // 每隔 2 秒检测一次
    weight -20  // 当脚本执行成立,那么把以后服务器优先级改为 -20
}
vrrp_instanceVI_1 {   // 每一个 vrrp_instance 就是定义一个虚构路由器
    state MASTER      // 主机为 MASTER,备用机为 BACKUP
    interface eth0    // 网卡名字,能够从 ifconfig 中查找
    virtual_router_id 51 // 虚构路由的 id 号,个别小于 255,主备机 id 须要一样
    priority 100      // 优先级,master 的优先级比 backup 的大
    advert_int 1      // 默认心跳距离
    authentication {  // 认证机制
        auth_type PASS
        auth_pass 1111   // 明码
    }
    virtual_ipaddress {  // 虚拟地址 vip
       172.16.2.8
    }
}

其中检测脚本 nginx_check.sh,这里提供一个:

#!/bin/bash
A=`ps -C nginx --no-header | wc -l`
if [$A -eq 0];then
    /usr/sbin/nginx # 尝试重新启动 nginx
    sleep 2         # 睡眠 2 秒
    if [`ps -C nginx --no-header | wc -l` -eq 0];then
        killall keepalived # 启动失败,将 keepalived 服务杀死。将 vip 漂移到其它备份节点
    fi
fi

复制一份到备份服务器,备份 Nginx 的配置要将 state 后改为 BACKUP,priority 改为比主机小。

设置结束后各自 service keepalived start 启动,通过拜访胜利之后,能够把 Master 机的 keepalived 停掉,此时 Master 机就不再是主机了 service keepalived stop,看拜访虚构 IP 时是否可能主动切换到备机 ip addr。

再次启动 Master 的 keepalived,此时 vip 又变到了主机上。

适配 PC 或挪动设施

依据用户设施不同返回不同款式的站点,以前常常应用的是纯前端的自适应布局,但无论是复杂性和易用性下面还是不如离开编写的好,比方咱们常见的淘宝、京东 …… 这些大型网站就都没有采纳自适应,而是用离开制作的形式,依据用户申请的 user-agent 来判断是返回 PC 还是 H5 站点。

首先在 /usr/share/nginx/html 文件夹下 mkdir 别离新建两个文件夹 PC 和 mobile,vim 编辑两个 index.html 轻易写点内容。

cd /usr/share/nginx/html
mkdir pc mobile
cd pc
vim index.html   # 轻易写点比方 hello pc!
cd ../mobile
vim index.html   # 轻易写点比方 hello mobile!

而后和设置二级域名虚拟主机时候一样,去 /etc/nginx/conf.d 文件夹下新建一个配置文件 fe.sherlocked93.club.conf:

# /etc/nginx/conf.d/fe.sherlocked93.club.conf

server {
  listen 80;
    server_name fe.sherlocked93.club;

    location / {
        root  /usr/share/nginx/html/pc;
    if ($http_user_agent ~* '(Android|webOS|iPhone|iPod|BlackBerry)') {root /usr/share/nginx/html/mobile;}
        index index.html;
    }

}

配置根本没什么不一样的,次要多了一个 if 语句,而后应用 $http_user_agent 全局变量来判断用户申请的 user-agent,指向不同的 root 门路,返回对应站点。

在浏览器拜访这个站点,而后 F12 中模仿应用手机拜访:

能够看到在模仿应用挪动端拜访的时候,Nginx 返回的站点变成了挪动端对应的 html 了。

配置 HTTPS

具体配置过程网上挺多的了,也能够应用你购买的某某云,个别都会有收费申请的服务器证书,装置间接看所在云的操作指南即可。

我购买的腾讯云提供的亚洲诚信机构颁发的收费证书只能一个域名应用,二级域名什么的须要另外申请,然而申请审批比拟快,个别几分钟就能胜利,而后下载证书的压缩文件,外面有个 nginx 文件夹,把 xxx.crt 和 xxx.key 文件拷贝到服务器目录,再配置下:

server {
  listen 443 ssl http2 default_server;   # SSL 拜访端口号为 443
  server_name sherlocked93.club;         # 填写绑定证书的域名
 
  ssl_certificate /etc/nginx/https/1_sherlocked93.club_bundle.crt;   # 证书文件地址
  ssl_certificate_key /etc/nginx/https/2_sherlocked93.club.key;      # 私钥文件地址
  ssl_session_timeout 10m;
 
  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;      #请依照以下协定配置
  ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
  ssl_prefer_server_ciphers on;
  
  location / {
    root         /usr/share/nginx/html;
    index        index.html index.htm;
  }
}

写完 nginx -t -q 校验一下,没问题就 nginx -s reload,当初去拜访 https://sherlocked93.club/ 就能拜访 HTTPS 版的网站了。

个别还能够加上几个加强安全性的命令:

add_header X-Frame-Options DENY;           # 缩小点击劫持
add_header X-Content-Type-Options nosniff; # 禁止服务器主动解析资源类型
add_header X-Xss-Protection 1;             # 防 XSS 攻打

一些罕用技巧

15.1 动态服务

server {
  listen       80;
  server_name  static.sherlocked93.club;
  charset utf-8;    # 避免中文文件名乱码
 
  location /download {
    alias              /usr/share/nginx/html/static;  # 动态资源目录
    
    autoindex               on;    # 开启动态资源列目录
    autoindex_exact_size    off;   # on(默认)显示文件的确切大小,单位是 byte;off 显示文件大略大小,单位 KB、MB、GB
    autoindex_localtime     off;   # off(默认)时显示的文件工夫为 GMT 工夫;on 显示的文件工夫为服务器工夫
  }
}

15.2 图片防盗链

server {
  listen       80;
  server_name  *.sherlocked93.club;

  # 图片防盗链

  location ~* \.(gif|jpg|jpeg|png|bmp|swf)$ {
    valid_referers none blocked 192.168.0.2;  # 只容许本机 IP 外链援用
    if ($invalid_referer){return 403;}
  }
}

15.3 申请过滤

# 非指定申请全返回 403

if ($request_method !~ ^(GET|POST|HEAD)$ ) {return 403;}

location / {

  # IP 拜访限度(只容许 IP 是 192.168.0.2 机器拜访)allow 192.168.0.2;
  deny all;

  root   html;
  index  index.html index.htm;
}

15.4 配置图片、字体等动态文件缓存

因为图片、字体、音频、视频等动态文件在打包的时候通常会减少了 hash,所以缓存能够设置的长一点,先设置强制缓存,再设置协商缓存;如果存在没有 hash 值的动态文件,倡议不设置强制缓存,仅通过协商缓存判断是否须要应用缓存。

# 图片缓存工夫设置

location ~ .*\.(css|js|jpg|png|gif|swf|woff|woff2|eot|svg|ttf|otf|mp3|m4a|aac|txt)$ {expires 10d;}

# 如果不心愿缓存

expires -1;

15.5 单页面我的项目 history 路由配置

server {
  listen       80;
  server_name  fe.sherlocked93.club;
  
  location / {
    root       /usr/share/nginx/html/dist;  # vue 打包后的文件夹
    index      index.html index.htm;
    try_files  $uri $uri/ /index.html @rewrites;
    
    expires -1;                          # 首页个别没有强制缓存
    add_header Cache-Control no-cache;
  }
  
  # 接口转发,如果需要的话
  #location ~ ^/api {
  #  proxy_pass http://be.sherlocked93.club;
  #}
  
  location @rewrites {rewrite ^(.+)$ /index.html break;
  }
}

15.6 HTTP 申请转发到 HTTPS

配置完 HTTPS 后,浏览器还是能够拜访 HTTP 的地址 http://sherlocked93.club/ 的,能够做一个 301 跳转,把对应域名的 HTTP 申请重定向到 HTTPS 上

server {
    listen      80;
    server_name www.sherlocked93.club;
 
    # 单域名重定向
    if ($host = 'www.sherlocked93.club'){return 301 https://www.sherlocked93.club$request_uri;}
    # 全局非 https 协定时重定向
    if ($scheme != 'https') {return 301 https://$server_name$request_uri;}
 
    # 或者全副重定向
    return 301 https://$server_name$request_uri;
 
    # 以上配置抉择本人须要的即可,不必全副加
}

15.7 泛域名门路拆散

这是一个十分实用的技能,常常有时候咱们可能须要配置一些二级或者三级域名,心愿通过 Nginx 主动指向对应目录,比方:

  1. test1.doc.sherlocked93.club 主动指向 /usr/share/nginx/html/doc/test1 服务器地址;
  2. test2.doc.sherlocked93.club 主动指向 /usr/share/nginx/html/doc/test2 服务器地址;
server {
    listen       80;
    server_name  ~^([\w-]+)\.doc\.sherlocked93\.club$;

    root /usr/share/nginx/html/doc/$1;

}

15.8 泛域名转发

和之前的性能相似,有时候咱们心愿把二级或者三级域名链接重写到咱们心愿的门路,让后端就能够依据路由解析不同的规定:

  1. test1.serv.sherlocked93.club/api?name=a 主动转发到 127.0.0.1:8080/test1/api?name=a;
  2. test2.serv.sherlocked93.club/api?name=a 主动转发到 127.0.0.1:8080/test2/api?name=a;
server {
    listen       80;
    server_name ~^([\w-]+)\.serv\.sherlocked93\.club$;

    location / {
        proxy_set_header        X-Real-IP $remote_addr;
        proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header        Host $http_host;
        proxy_set_header        X-NginX-Proxy true;
        proxy_pass              http://127.0.0.1:8080/$1$request_uri;
    }

}
退出移动版