Nginx简介:
先引用一段来自百度百科的介绍:
Nginx (engine x) 是一个高性能的HTTP和反向代理web服务器,同时也提供了IMAP/POP3/SMTP服务。Nginx是由伊戈尔·赛索耶夫为俄罗斯访问量第二的Rambler.ru站点(俄文:Рамблер)开发的,第一个公开版本0.1.0发布于2004年10月4日。
其将源代码以类BSD许可证的形式发布,因它的稳定性、丰富的功能集、示例配置文件和低系统资源的消耗而闻名。2011年6月1日,nginx 1.0.4发布。
Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,在BSD-like 协议下发行。其特点是占有内存少,并发能力强,事实上nginx的并发能力在同类型的网页服务器中表现较好
这篇文章我们暂时只关注这个部分:
Nginx配置:
先上一张图:
然后针对一些功能和配置展开来讲讲。
负载均衡(主要是后端人员配置)
当一个应用单位时间内访问量激增,服务器的带宽及性能受到影响,影响大到自身承受能力时,服务器就会宕机奔溃,为了防止这种现象发生,以及实现更好的用户体验,我们可以通过配置Nginx负载均衡的方式来分担服务器压力
当有一台服务器宕机时,负载均衡器就分配其他的服务器给用户,极大的增加的网站的稳定性 当用户访问web时候,首先访问到的是负载均衡器,再通过负载均衡器将请求转发给后台服务器
1.1 负载均衡的几种常用方式
-
轮询(默认)
// nginx.config
upstream backserver {
server 192.168.0.1;
server 192.168.0.2;
}
-
权重weight
指定不同ip的权重,权重与访问比成正相关,权重越高,访问越大,适用于不同性能的机器
// nginx.config
upstream backserver {
server 192.168.0.1 weight=2;
server 192.168.0.2 weight=8;
}
-
响应时间来分配
公平竞争,谁相应快,谁处理,不过这种方式需要依赖到第三方插件nginx-upstream-fair,需要先安装
// nginx.config
upstream backserver {
server 192.168.0.1;
server 192.168.0.2;
fair;
}
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://backserver;
}
}
1.2 健康检查
Nginx 自带 ngx_http_upstream_module(健康检测模块)本质上服务器心跳的检查,通过定期轮询向集群里的服务器发送健康检查请求,来检查集群中是否有服务器处于异常状态
如果检测出其中某台服务器异常,那么在通过客户端请求nginx反向代理进来的都不会被发送到该服务器上(直至下次轮训健康检查正常)
基本例子如下👇
upstream backserver{
server 192.168.0.1 max_fails=1 fail_timeout=40s;
server 192.168.0.2 max_fails=1 fail_timeout=40s;
}
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://backend;
}
}
涉及两个配置:
-
fail_timeout : 设定服务器被认为不可用的时间段以及统计失败尝试次数的时间段,默认为10s
-
max_fails : 设定Nginx与服务器通信的尝试失败的次数,默认为:1次
反向代理,解决跨域问题 (前后端都需要了解)
反向代理指的是,当一个客户端发送的请求,想要访问服务器上的内容,但将被该请求先发送到一个代理服务器proxy,这个代理服务器(Nginx)将把请求代理到和自己属于同一个局域网下的内部服务器上,而用户通过客户端真正想获得的内容就存储在这些内部服务器上,此时Nginx代理服务器承担的角色就是一个中间人,起到分配和沟通的作用
2.1 为什么需要反向代理?
反向代理的优势主要有以下两点
-
防火墙作用
当你的应用不想直接暴露给客户端(也就是客户端无法直接通过请求访问真正的服务器,只能通过Nginx),通过nginx过滤掉没有权限或者非法的请求,来保障内部服务器的安全
-
负载均衡
也就上一章提到负载均衡,本质上负载均衡就是反向代理的一种应用场景,可以通过nginx将接收到的客户端请求"均匀地"分配到这个集群中所有的服务器上(具体看负载均衡方式),从而实现服务器压力的负载均衡
2.2 如何使用反向代理解决前端跨域问题
前端跨域问题由来:
跨域问题的由来是浏览器的同源策略。
所谓同源是指,域名,协议,端口相同。浏览器执行javascript脚本时,会检查这个脚本属于那个页面,如果不是同源页面,就不会被执行。跨域情况如下:
由此可知,就算前后端部署在同一台服务器上,如果不是起在同一个应用服务器中,那么跨域问题还是存在,因为两个服务的端口不同。那么如何来解决这个问题呢?
常用的跨域解决方法
-
1.jsonp 需要目标服务器配合一个callback函数。
-
2.window.name+iframe 需要目标服务器响应window.name。
-
3.window.location.hash+iframe 同样需要目标服务器作处理。
-
4.html5的 postMessage+ifrme 这个也是需要目标服务器或者说是目标页面写一个postMessage,主要侧重于前端通讯。
-
5.CORS 需要服务器设置header :Access-Control-Allow-Origin。
-
6.nginx反向代理 这个方法一般很少有人提及,但是他可以不用目标服务器配合,不过需要你搭建一个中转nginx服务器,用于转发请求。
我们这里将的就是通过nginx反向代理的方式解决跨域问题。
在 Nginx 反向代理是,会通过 location 功能匹配指定的 URI,然后把接收到的符合匹配 URI的请求通过 proxy_pass 转移给之前定义好的 upstream 节点池。
先看一个简单的例子:
upstream authorize_{
ip_hash;
server 127.0.0.1:81;
}
upstream oauth_{
ip_hash;
server 127.0.0.1:88;
}
server {
listen 89; // nginx监听的端口,默认是80。可以手动修改,其实也就是到时候前端页面访问的端口
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root /program/TyAuthorization/www/;
index index.html index.htm;
}
location /authorize{
proxy_pass http://authorize_/api/v1/authorize;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
}
location /oauth{
proxy_pass http://oauth_/oauth;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
}
location /files {
alias /program/web/static/;
autoindex on;
}
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
说明:nginx监听89端口,可以手动修改,其实也就是到时候前端页面访问的端口。所有到这个端口的请求都通过nginx来转发,默认会进到root目录下的静态页面 , 也就是 location / 这条协议路径。
但是当请求匹配到“/authorize_”或者“/oauth_”等协议路径时,则该请求会被转发到上面配置的upstream对应的server地址上,而匹配到“/files”时,则直接访问当前nginx服务器的本地路径:/program/web/static/, 这种情况一般用来预览或者下载文件。
PS: location 后面跟的协议路径是可以使用正则表达式的,如:
location ~* \.(png|gif|jpg|jpeg)$ {
root pragram/web/static/;
autoindex on;
access_log off;
expires 10h;# 设置过期时间为 10 小时
}
匹配以png|gif|jpg|jpeg
为结尾的请求,并将请求转发到本地路径。
Gzip 配置开启 文件压缩
GZIP
是规定的三种标准 HTTP 压缩格式之一。目前绝大多数的网站都在使用GZIP
传输 HTML
、CSS
、JavaScript
等资源文件。
对于文本文件,GZip
的效果非常明显,开启后传输所需流量大约会降至 1/4 ~ 1/3
。
并不是每个浏览器都支持gzip
的,如何知道客户端是否支持gzip
呢,请求头中的Accept-Encoding
来标识对压缩的支持。
启用gzip
同时需要客户端和服务端的支持,如果客户端支持gzip
的解析,那么只要服务端能够返回gzip
的文件就可以启用gzip
了, 我们可以通过nginx
的配置来让服务端支持gzip
。下面的respone
中content-encoding:gzip
,指服务端开启了gzip
的压缩方式。
在nginx配置中,把gzip 设置为on, 就表示开启了gzip
gzip on;
gzip_http_version 1.1;
gzip_comp_level 5;
gzip_min_length 1000;
gzip_types text/csv text/xml text/css text/plain text/javascript application/javascript application/x-javascript application/json application/xml;
gzip
-
开启或者关闭
gzip
模块 -
默认值为
off
-
可配置为
on / off
gzip_http_version
-
启用
GZip
所需的HTTP
最低版本 -
默认值为
HTTP/1.1
这里为什么默认版本不是1.0
呢?
HTTP
运行在TCP
连接之上,自然也有着跟TCP
一样的三次握手、慢启动等特性。
启用持久连接情况下,服务器发出响应后让TCP
连接继续打开着。同一对客户 / 服务器之间的后续请求和响应可以通过这个连接发送。
为了尽可能的提高 HTTP
性能,使用持久连接就显得尤为重要了。
HTTP/1.1
默认支持TCP
持久连接,HTTP/1.0
也可以通过显式指定 Connection: keep-alive
来启用持久连接。
看一下对比:
不开启gzip:
开启gizp
开启之后,Content-Encoding: gzip; ETag: W/"~~~";
这里的ETag
中的 W\
就是区分是否是在线写入压缩的标识;
开启gzip
,298KB
可以减少到 104KB
,效率还是不错的;
但是,对于很多前端项目来说,只是开启gzip是不够的。
继续来说说 gzip_static
在前端代码打包构建bundle
的时候,一般都有根据一定的算法自动压缩代码成gz
文件的webpack
插件;
当我们不在 nginx
开启 gzip_static
的时候,发现生产的gz
文件并没有被运行,这个时候其实是无效的,它并没有加载前端打包之后的.gz文件。
而gzip_static
是会自动执行gz
文件的,这样的就避免了通过gzip
自动压缩;
我们上面讲到通过gzip
自动压缩是 104KB
,而我们自己压缩的是90KB
,所有如果运行了我们自己的gz
文件,会更好。
所以,gzip static 也需要设置为 on
gzip on;
gzip static on;
gzip_http_version 1.1;
gzip_comp_level 5;
gzip_min_length 1000;
gzip_types text/csv text/xml text/css text/plain text/javascript application/javascript application/x-javascript application/json application/xml;
但是nginx上配置gzip static会遇到一些问题,具体可以参考我之前的文章:
https://blog.csdn.net/yorcentroll/article/details/102686680
请求过滤
根据状态码过滤
error_page 500 501 502 503 504 506 /50x.html;
location = /50x.html {
# 将跟路径改编为存放 html 的路径。
root /root/static/html;
}
根据 URL 名称过滤,精准匹配 URL,不匹配的 URL 全部重定向到主页。
location / {
rewrite ^.*$ /index.html redirect;
}
根据请求类型过滤。
if ( $request_method !~ ^(GET|POST|HEAD)$ ) {
return 403;
}
适配PC与移动环境
当用户从移动端打开PC端baidu.com的场景时,将自动跳转指移动端m.baidu.com,本质上是Nginx可以通过内置变量$http_user_agent,获取到请求客户端的userAgent,从而知道当前用户当前终端是移动端还是PC,进而重定向到H5站还是PC站
server {
location / {
//移动、pc设备agent获取
if ($http_user_agent ~* '(Android|webOS|iPhone)') {
set $mobile_request '1';
}
if ($mobile_request = '1') {
rewrite ^.+ http://m.baidu.com;
}
}
}
Nginx配置https
要开启 HTTPS 服务,在配置文件信息块(server),必须使用监听命令 listen 的 ssl 参数和定义服务器证书文件和私钥文件,如下所示:
server {
#ssl参数
listen 443 ssl; //监听443端口,因为443端口是https的默认端口。80为http的默认端口
server_name example.com;
#证书文件
ssl_certificate example.com.crt;
#私钥文件
ssl_certificate_key example.com.key;
}
复制代码
-
ssl_certificate:证书的绝对路径
-
ssl_certificate_key: 密钥的绝对路径;
vue history路由配置修改:
如果路由模式为history模式,那么前端打包后的文件部署到nginx后需要加一个配置
location / {
root /program/TyAuthorization/www/;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
就是这个 try_files $uri $uri/ /index.html; 如果是hash模式,不需要配这行,history需要加上这行,否则多级路由的页面是访问不了的。
一些其他配置
keepalive_timeout 65;
#request的header中包含’_’时,不忽略。 比如如果header里面加了access_token这个字段,不加这个 on, 那就有问题,access_token识别不了。
underscores_in_headers on;
附上一份平时用到的配置:
#user nobody;
worker_processes 4;
error_log /usr/local/nginx/logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid /program/nginx/nginx.pid;
events {
use epoll;
worker_connections 4096;
}
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 /usr/local/nginx/logs/access.log main;
client_max_body_size 20M;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#request的header中包含’_’时,不忽略
underscores_in_headers on;
gzip on;
gzip_static on;
gzip_proxied expired no-cache no-store private auth;
gzip_disable "msie6"; #不使用gzip IE6
gzip_min_length 1024; #gzip压缩最小文件大小,超出进行压缩(自行调节)
gzip_buffers 4 16k; #buffer 不用修改
gzip_comp_level 3; #压缩级别:1-10,数字越大压缩的越好,时间也越长
gzip_types text/plain application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png; # 压缩文件类型
gzip_vary off; #跟Squid等缓存服务有关,on的话会在Header里增加 "Vary: Accept-Encoding"
upstream authorize_{
ip_hash;
server 127.0.0.1:81;
}
upstream oauth_{
ip_hash;
server 127.0.0.1:88;
}
server {
listen 89;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root /program/web/www/;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
location /authorize{
proxy_pass http://authorize_/api/v1/authorize;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
}
#location /oauth{
# proxy_pass http://oauth_/oauth;
# proxy_redirect off;
# proxy_set_header Host $host;
# proxy_set_header X-Forwarded-For $remote_addr;
#}
location /client{
proxy_pass http://authorize_/client;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
}
location /files/ {
alias /program/TyAuthorization/static/;
autoindex on;
}
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
一些基本命令
nginx -t 检查配置文件是否有语法错误
nginx -s reload 热加载,重新加载配置文件
nginx -s stop 快速关闭
nginx -s quit 等待工作进程处理完成后关闭
参考文章:
https://mp.weixin.qq.com/s/wecUdGnuHdZOs3t7zc16jw
https://mp.weixin.qq.com/s/czV9m-jslpEUnvX39nduYw
如有问题或建议,请多多提出,如发现错误,烦请指正。