Nginx
常用命令:
nginx -s stop 快速关闭Nginx,可能不保存相关信息,并迅速终止web服务。
nginx -s quit 平稳关闭Nginx,保存相关信息,有安排的结束web服务。
nginx -s reload 因改变了Nginx相关配置,需要重新加载配置而重载。
nginx -s reopen 重新打开日志文件。
nginx -c filename 为 Nginx 指定一个配置文件,来代替缺省的。
nginx -t 不运行,仅仅测试配置文件。nginx 将检查配置文件的语法的正确性,并尝试打开配置文件中所引用到的文件。
nginx -v 显示 nginx 的版本。
nginx -V 显示 nginx 的版本,编译器版本和配置参数。
如果不想每次都敲命令,可以在 nginx 安装目录下新添一个启动批处理文件startup.bat,双击即可运行。内容如下:
@echo off
rem 如果启动前已经启动nginx并记录下pid文件,会kill指定进程
nginx.exe -s stoprem 测试配置文件语法正确性
nginx.exe -t -c conf/nginx.confrem 显示版本信息
nginx.exe -vrem 按照指定配置去启动nginx
nginx.exe -c conf/nginx.conf
Http 反向代理
nginx.conf 配置文件如下:
注:conf/nginx.conf 是 nginx 的默认配置文件。你也可以使用 nginx -c 指定你的配置文件
#运行用户
#user somebody;#启动进程,通常设置成和cpu的数量相等
worker_processes 1;#全局错误日志
error_log D:/Tools/nginx-1.10.1/logs/error.log;
error_log D:/Tools/nginx-1.10.1/logs/notice.log notice;
error_log D:/Tools/nginx-1.10.1/logs/info.log info;#PID文件,记录当前启动的nginx的进程ID
pid D:/Tools/nginx-1.10.1/logs/nginx.pid;#工作模式及连接数上限
events {worker_connections 1024; #单个后台worker process进程的最大并发链接数
}#设定http服务器,利用它的反向代理功能提供负载均衡支持
http {#设定mime类型(邮件支持类型),类型由mime.types文件定义include D:/Tools/nginx-1.10.1/conf/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 D:/Tools/nginx-1.10.1/logs/access.log main;rewrite_log on;#sendfile 指令指定 nginx 是否调用 sendfile 函数(zero copy 方式)来输出文件,对于普通应用,#必须设为 on,如果用来进行下载等应用磁盘IO重负载应用,可设置为 off,以平衡磁盘与网络I/O处理速度,降低系统的uptime.sendfile on;#tcp_nopush on;#连接超时时间keepalive_timeout 120;tcp_nodelay on;#gzip压缩开关#gzip on;#设定实际的服务器列表upstream zp_server1{server 127.0.0.1:8089;}#HTTP服务器server {#监听80端口,80端口是知名端口号,用于HTTP协议listen 80;#定义使用www.xx.com访问server_name www.helloworld.com;#首页index index.html#指向webapp的目录root D:\01_Workspace\Project\github\zp\SpringNotes\spring-security\spring-shiro\src\main\webapp;#编码格式charset utf-8;#代理配置参数proxy_connect_timeout 180;proxy_send_timeout 180;proxy_read_timeout 180;proxy_set_header Host $host;proxy_set_header X-Forwarder-For $remote_addr;#反向代理的路径(和upstream绑定),location 后面设置映射的路径location / {proxy_pass http://zp_server1;}#静态文件,nginx自己处理location ~ ^/(images|javascript|js|css|flash|media|static)/ {root D:\01_Workspace\Project\github\zp\SpringNotes\spring-security\spring-shiro\src\main\webapp\views;#过期30天,静态文件不怎么更新,过期可以设大一点,如果频繁更新,则可以设置得小一点。expires 30d;}#设定查看Nginx状态的地址location /NginxStatus {stub_status on;access_log on;auth_basic "NginxStatus";auth_basic_user_file conf/htpasswd;}#禁止访问 .htxxx 文件location ~ /\.ht {deny all;}#错误处理页面(可选择性配置)#error_page 404 /404.html;#error_page 500 502 503 504 /50x.html;#location = /50x.html {# root html;#}}
}
好了,让我们来试试吧:
1.启动 webapp,注意启动绑定的端口要和 nginx 中的 upstream 设置的端口保持一致。
2.更改 host:在 C:\Windows\System32\drivers\etc 目录下的 host 文件中添加一条 DNS 记录
127.0.0.1 www.helloworld.com
3.启动前文中 startup.bat 的命令
4.在浏览器中访问 www.helloworld.com,不出意外,已经可以访问了。
Https 反向代理
一些对安全性要求比较高的站点,可能会使用 HTTPS(一种使用 ssl 通信标准的安全 HTTP 协议)。
这里不科普 HTTP 协议和 SSL 标准。但是,使用 nginx 配置 https 需要知道几点:
- HTTPS 的固定端口号是 443,不同于 HTTP 的 80 端口
- SSL 标准需要引入安全证书,所以在 nginx.conf 中你需要指定证书和它对应的 key
其他和 http 反向代理基本一样,只是在 Server 部分配置有些不同。
#HTTP服务器server {#监听443端口。443为知名端口号,主要用于HTTPS协议listen 443 ssl;#定义使用www.xx.com访问server_name www.helloworld.com;#ssl证书文件位置(常见证书文件格式为:crt/pem)ssl_certificate cert.pem;#ssl证书key位置ssl_certificate_key cert.key;#ssl配置参数(选择性配置)ssl_session_cache shared:SSL:1m;ssl_session_timeout 5m;#数字签名,此处使用MD5ssl_ciphers HIGH:!aNULL:!MD5;ssl_prefer_server_ciphers on;location / {root /root;index index.html index.htm;}}
1.反向代理
反向代理(Reverse Proxy)方式是指以代理服务器来接受 internet 上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给 internet 上请求连接的客户端,此时代理服务器对外就表现为一个反向代理服务器。
接下来我们开始用一个小demo来演示反向代理的使用
1.1 服务准备
首先将我本地的一个服务打成 胖jar:
然后使用java -jar方式启动服务,且指定端口为8081:
java -jar /Users/hzz/myself_project/xzll/study-admin/study-admin-service/target/study-admin-service.jar --server.port=8081
最后使用postman测试接口是否正常(注意此时还没被nginx代理,而是直接调的服务):
启动服务并验证接口无误后,接下来我们修改nginx配置文件。让nginx反向代理我们的服务。
1.2 修改nginx.conf文件
要让 nginx 代理 我们的 服务 很简单,简单描述一下就是 两步:
1.通过upstream指令块来定义我们的上游服务(即被代理的服务)
2.通过location指令块中的 proxy_pass指令,指定该location要路由到哪个upstream
配置好1和2后,如果来了请求后 会通过url路由到对应的location, 然后nginx会将请求打到upstream定义的服务地址中去,下边我们看看:
使用 vi /etc/nginx/nginx.conf命令修改nginx.conf文件,如下:
注意上边的 proxy_pass http://mybackendserver/ 后边这个斜线加和不加区别挺大的,加的话不会拼接/backend , 而不加的话会拼接 /backend
1.3 测试反向代理
1.4 反向代理流程与原理
对于上边演示的反向代理案例的流程与原理,我们来个示意图如下:(这个图比较重要)
2. 负载均衡
说到负载均衡很多人应该并不陌生,总而言之负载均衡就是:避免高并发高流量时请求都聚集到某一个服务或者某几个服务上,而是让其均匀分配(或者能者多劳),从而减少高并发带来的系统压力,从而让服务更稳定。对于nginx来说,负载均衡就是从 upstream 模块定义的后端服务器列表中按照配置的负载策略选取一台服务器接受用户的请求。
2.1 准备3个不同端口的springboot服务
想要演示负载均衡,我们首先得多搞几个服务,搞一个服务是没法儿演示的。所以我启动了3个不同端口(8081,8082,8083)的springboot服务,如下:
java -jar /Users/hzz/myself_project/xzll/study-admin/study-admin-service/target/study-admin-service.jar --server.port=8081
java -jar /Users/hzz/myself_project/xzll/study-admin/study-admin-service/target/study-admin-service.jar --server.port=8082
java -jar /Users/hzz/myself_project/xzll/study-admin/study-admin-service/target/study-admin-service.jar --server.port=8083
使用 command+D 对iterm2进行分屏 ,最左侧是8081端口,中间是8082,右侧是8083:
接下来我们说一下负载策略再开始
2.2 nginx常用的负载策略:
2.3 轮询
轮询策略是默认的,所以只需要如下这样修改配置文件就可以了:
重启nginx后观察一下:
以上图片可以看到,是按upstream中的先后顺序来进行轮询的。
2.4 weight
weight指令用于指定轮询机率,weight的默认值为1,weight的数值与访问比率成正比。 接下来我们指定8082端口的服务的weight=2,如下:
看下权重策略下的请求结果:
可以看到在一轮轮询中,8081命中1次,8082由于配置了 weight=2所以命中了2次,8083命中了1次。即配置了weight=2的8082服务,命中几率是8081或者8083的两倍
2.5 ip_hash
设定ip哈希很简单,就是在你的upstream中 指定 ip_hash;即可,如下
重启nginx后看下效果:
可以看到,由于我的访问ip总是固定的宿主机的172.30.128.64 根据hash算法我的ip被匹配给了8083端口的服务,所以只要我不换ip 不管我请求多少次,请求都是被 转发到了8083的服务上了
2.6 least_conn
同ip_hash一样,设定最小连接数策略也很简单,就是在你的upstream中 指定 least_conn;即可,如下
3. 动静分离
在说动静分离前,我们要知道为何要做动静分离以及他能解决啥问题,首先,我们常见的web系统中会有大量的静态资源文件比如掘金主页面刷新后的f12如下:
可以看到有很多静态资源,如果将这些资源都搞到后端服务的话,将会提高后端服务的压力且占用带宽增加了系统负载(要知道,静态资源的访问频率其实蛮高的)所以为了避免该类问题我们可以把不常修改的静态资源文件放到nginx的静态资源目录中去,这样在访问静态资源时直接读取nginx服务器本地文件目录之后返回,这样就大大减少了后端服务的压力同时也加快了静态资源的访问速度,何为静,何为动呢?: 1. 静: 将不常修改且访问频繁的静态文件,放到nginx本地静态目录(当然也可以搞个静态资源服务器专门存放所有静态文件) 2. 动: 将变动频繁/实时性较高的比如后端接口,实时转发到对应的后台服务
接下来我们将构造一个html页面,然后点击按钮后发送get请求到后端接口。流程如下:
3.1 准备工作
首先我们搞个html(请原谅我这粗糙的前端代码 ),内容如下:
之后使用
scp /Users/hzz/fsdownload/index_page.html root@172.30.128.65:/usr/local/nginx/test/static
命令将index_page.html 文件上传到虚拟机。
3.2 修改nginx.conf文件
首先我们配置俩location规则,一个( /frontend )是读取静态文件,一个(/backend)是转发到 我们配置的upstream服务中去。如下:
3.3 演示
首先我们在浏览器输入:http://www.proxytest.com/frontend/ ,可以看到请求返回了一个html页面,其实就是我们刚才的 /usr/local/nginx/test/static/index_page.html文件
接着我们输入要查询的人名,之后点击 “调用get接口” 按钮,如下:
返回数据:
4.跨域
4.1 为何会产生跨域?
产生跨域问题的主要原因就在于同源策略,为了保证用户信息安全,防止恶意网站窃取数据,同源策略是必须的,该政策由 Netscape 公司于1995年引入浏览器。目前,所有浏览器都实行这个政策。同源策略主要是指三点相同即:协议+域名+端口 相同的两个请求,则可以被看做是同源的,但如果其中任意一点存在不同,则代表是两个不同源的请求,同源策略会限制不同源之间的资源交互从而减少数据安全问题。
4.2 跨域演示
首先我在nginx.conf文件中加一个server配置也即将前后端配成不同的server 并且监听的端口以及域名名称都不一致,从而造成访问前端服务和后端服务时候 这俩服务不是"同源", 如下:
之后我修改index_page中的后端地址:
重启nginx,并配置宿主机的hosts文件:
172.30.128.65 www.front.com
172.30.128.65:90 www.backend.com
之后在浏览器中测试一下:
可以看到浏览器提示我们受同源规则影响我们不能跨域访问资源。造成的原因是我的两个域名解析出来的端口不一致 一个是80一个是90。不符合同源策略,所以必然会有跨域报错。
4.3 nginx解决跨域
首先想解决跨越就得避免不同源,而我们可不可以 把对后端的代理 放在前端的server中呢(也就是说让前后端统一使用一个端口,一个server_name)?答案是可以的,因为server支持多个location配置呀(一个location处理前端,一个location转发后端),我们改下配置文件试一把如下:
之后重启nginx后在浏览器输入 http://www.xxxadminsystem.com/page/ ,效果如下:
上边/page请求返回了html页面之后我们输入参数点击“调用get接口”查看到后端接口的调用如下:
从上边可以看到,我上边设想的方式是可行的。
4.4 nginx解决跨域
web 领域开发中,经常采用前后端分离模式。这种模式下,前端和后端分别是独立的 web 应用程序,例如:后端是 Java 程序,前端是 React 或 Vue 应用。
各自独立的 web app 在互相访问时,势必存在跨域问题。解决跨域问题一般有两种思路:
1.CORS
在后端服务器设置 HTTP 响应头,把你需要允许访问的域名加入 Access-Control-Allow-Origin 中。
2.jsonp
把后端根据请求,构造 json 数据,并返回,前端用 jsonp 跨域。
这两种思路,本文不展开讨论。
需要说明的是,nginx 根据第一种思路,也提供了一种解决跨域的解决方案。
举例:www.helloworld.com 网站是由一个前端 app ,一个后端 app 组成的。前端端口号为 9000, 后端端口号为 8080。
前端和后端如果使用 http 进行交互时,请求会被拒绝,因为存在跨域问题。来看看,nginx 是怎么解决的吧:
首先,在 enable-cors.conf 文件中设置 cors :
# allow origin list
set $ACAO '*';# set single origin
if ($http_origin ~* (www.helloworld.com)$) {set $ACAO $http_origin;
}if ($cors = "trueget") {add_header 'Access-Control-Allow-Origin' "$http_origin";add_header 'Access-Control-Allow-Credentials' 'true';add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
}if ($request_method = 'OPTIONS') {set $cors "${cors}options";
}if ($request_method = 'GET') {set $cors "${cors}get";
}if ($request_method = 'POST') {set $cors "${cors}post";
}
接下来,在你的服务器中 include enable-cors.conf 来引入跨域配置:
# ----------------------------------------------------
# 此文件为项目 nginx 配置片段
# 可以直接在 nginx config 中 include(推荐)
# 或者 copy 到现有 nginx 中,自行配置
# www.helloworld.com 域名需配合 dns hosts 进行配置
# 其中,api 开启了 cors,需配合本目录下另一份配置文件
# ----------------------------------------------------
upstream front_server{server www.helloworld.com:9000;
}
upstream api_server{server www.helloworld.com:8080;
}server {listen 80;server_name www.helloworld.com;location ~ ^/api/ {include enable-cors.conf;proxy_pass http://api_server;rewrite "^/api/(.*)$" /$1 break;}location ~ ^/ {proxy_pass http://front_server;}
}
到此,就完成了。