Nginx部署前端需要了解的知识
Nginx部署前端项目
Nginx 是一个高性能的HTTP和反向代理服务器。作为前端开发的同学,了解反向代理的概念是非常必要的,特别是在构建现代应用时。
反向代理的基本概念
反向代理与正向代理的区别在于代理对象的不同。正向代理是客户端主动通过代理服务器访问互联网,例如使用 VPN 翻墙。当我们访问国外网站时,可能会遇到速度慢或无法访问的问题,这时正向代理可以帮助我们解决这些问题。
与之相对,反向代理则是在服务器端,通过反向代理服务器来选择目标服务器处理请求。客户端无需配置,只需将请求发送到反向代理服务器,由它来获取数据并返回给客户端。这种方式不仅隐藏了真实服务器的 IP 地址,还能够将请求分发到多台后端服务器,从而提高系统的可用性和负载均衡能力,增强整体安全性。
反向代理工作原理
客户端配置代理服务器,通过代理服务器进行互联网访问。代理对象是客户端,而服务端则隐藏在反向代理之后。简单来说,当用户请求资源时,反向代理服务器会处理这些请求并转发到合适的后端服务器。这样,外部用户只需知道反向代理的地址,而不需要知道真实的服务器地址。
nginx的配置文件目录
- /etc/nginx/nginx.conf 核心配置文件
- /etc/nginx/conf.d/default.conf 默认http服务器配置文件
- /etc/nginx/fastcgi_params fastcgi配置
- /etc/nginx/scgi_params scgi配置
- /etc/nginx/uwsgi_params uwsgi配置
- /etc/nginx/koi-utf
- /etc/nginx/koi-win
- /etc/nginx/win-utf 这三个文件是编码映射文件,因为作者是俄国人
- /etc/nginx/mime.types 设置HTTP协议的Content-Type与扩展名对应关系的文件
- /usr/lib/systemd/system/nginx-debug.service
- /usr/lib/systemd/system/nginx.service
- /etc/sysconfig/nginx
- /etc/sysconfig/nginx-debug 这四个文件是用来配置守护进程管理的
- /etc/nginx/modules 基本共享库和内核模块
- /usr/share/doc/nginx-1.18.0 帮助文档
- /usr/share/doc/nginx-1.18.0/COPYRIGHT 版权声明
- /usr/share/man/man8/nginx.8.gz 手册
- /var/cache/nginx Nginx的缓存目录
- /var/log/nginx Nginx的日志目录
- /usr/sbin/nginx 可执行命令
- /usr/sbin/nginx-debug 调试执行可执行命令
nginx核心模块
nginx的核心配置文件nginx.conf主要由3个部分组成:
基本配置
#user nobody; #配置worker进程运行用户
worker_processes 1; #配置工作进程数目,根据硬件调整,通常等于CPU数量或者2倍于CPU数量
#error_log logs/error.log; # 配置全局错误日志及类型
events配置
events {
worker_connections 1024; #配置每个worker进程连接数上限,nginx支持的总连接数等于worker_connections*worker_processes
}
http基本配置
http {
include mime.types;
default_type application/octet-stream;
client_max_body_size 100m;
sendfile on; #开启高效文件传输模式
#tcp_nopush on; #防止网络阻塞
keepalive_timeout 0;
gzip on; //启动
gzip_buffers 32 4K;
gzip_comp_level 6; //压缩级别,1-10,数字越大压缩的越好
gzip_min_length 100; //不压缩临界值,大于100的才压缩,一般不用改
gzip_types application/javascript text/css text/xml;
}
client_max_body_size
表示 客户端请求服务器最大允许大小,如果请求正文数据大于设定值,HTTP协议会报413错误Request Entity Too Large
,如果需要上传大文件是需要修改这个值的。keepalive_timeout
:长连接超时时间,单位是秒,Nginx
使用keepalive_timeout
来指定KeepAlive
的超时时间(timeout)。指定每个 TCP 连接最多可以保持多长时间。
Nginx 的默认值是 75 秒,有些浏览器最多只保持60
秒,所以可以设定为60
秒。若将它设置为 0,就禁止了 keepalive 连接。做好这些超时时间的限定,
判定超时后资源被释放,用来处理其他的请求,以此提升Nginx
的性能gzip
:在不设置服务器gzip的情况下,我们访问网站
设置了gzip后访问情况如下
- 经过对比,我们发现,设置gzip之后,获取同样的数据。压缩之后的数据量大概是原始数据的1/4。同样的,获取数据的时间也大大降低。极大的优化了用户的体验。
Server配置
server {
listen 80;
server_name localhost;
# 定义根目录
root /home/test;
# 主要的请求处理
location / {
##默认的匹配斜杠/的请求,当访问路径中有/,会被该localtion匹配到并进行处理
try_files $uri $uri/ /index.html;
index index.html;
}
# API请求代理
location /api {
proxy_pass http://ip; # 替换为实际API的URL
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# 静态资源处理
location ~* \.(gif|jpg|jpeg|png|css|js|ico)$ {
root /home/test/html/static;
}
# 图片防盗链
location ~* \.(jpg|jpeg|png|gif|webp)$ {
valid_referers none blocked *.deeruby.com;
if ($invalid_referer) {
return 403;
}
}
# 静态文件访问限制
location /static {
allow 39.xxx.xxx.xxx;
deny all;
}
# 自定义404错误页面
error_page 404 /404.html;
}
location / {
try_files $uri $uri/ /index.html;
}
-
以上这段代码主要是为了解决vue项目history模式下刷新页面出现404的问题,目前开发 使用一般前后端分离技术,并且前端负责路由。为了美观,会采用前端会采用history 模式的路由。但刷新页面时,前端真的会按照假路由去寻找文件。此时,必须返回index(index.html)文件才不至于返回404,如果没有使用该段代码,地址栏的#号依旧会消失,但是你无法通过直接输入路由地址直接进入到对应的页面。主要原因是路由的路径资源并不是一个真实的路径,所以无法找到具体的文件因此需要
rewrite
到index.html中,然后交给路由在处理请求资源,try_files
为文件匹配,先找真实的地址($uri),如果找不到,再找index.html
文件 -
error_page
在一次请求中只能响应一次,对应的Nginx
有另外一个配置可以控制这个选项:recursive_error_pages
默认为false,作用是控制error_page能否在一次请求中触发多次。
在这里特别注意一下关于proxy_pass处理代理时url末尾 带/
与不带/
的区别
-
proxy_pass配置中url末尾带/时,nginx转发时,会将原uri去除location匹配表达式后的内容拼接在proxy_pass中url之后。
测试地址:http://ip 场景一: location ^~ /test/ { proxy_pass http://ip/server/; } 代理后实际访问地址:http://ip/server/api 场景二: location ^~ /test { proxy_pass http://ip/server/; } 代理后实际访问地址:http://ip/server//api 场景三: location ^~ /test/ { proxy_pass http://ip/; } 代理后实际访问地址:http://ip/api 场景四: location ^~ /test { proxy_pass http://ip/; } 代理后实际访问地址:http://ip//api
-
proxy_pass配置中url末尾不带/时,如url中不包含path,则直接将原uri拼接在proxy_pass中url之后;如url中包含path,则将原uri去除location匹配表达式后的内容拼接在proxy_pass中的url之后
测试地址:http://ip
场景一:
location ^~ /test/{
proxy_pass http://ip/server;
}
代理后实际访问地址:http://ip/serverapi
场景二:
location ^~ /test {
proxy_pass http://ip/server;
}
代理后实际访问地址:http://ip/server/api
场景三:
location ^~ /test/ {
proxy_pass http://ip;
}
代理后实际访问地址:http://ip
场景四:
location ^~ /test {
proxy_pass http://ip;
}
代理后实际访问地址:http://ip
关于Nginx location匹配规则
-
Nginx 的 location 实现了对请求的细分处理,有些 URI 返回静态内容,有些分发到后端服务器等,在这里我们也做一个梳理:
location 支持的语法 location [=|~|~*|^~] pattern { ... }
「=」 修饰符:要求路径完全匹配
server {
server_name baidu.com;
location = /wsknet {
[…]
}
}
http://baidu.com/wsknet
匹配http://baidu.com/WSKNET
可能会匹配 ,也可以不匹配,取决于操作系统的文件系统是否大小写敏感(case-sensitive)。ps: Mac 默认是大小写不敏感的,git 使用会有大坑。http://baidu.com/wsknet?param1¶m2
匹配,忽略 querystringhttp://baidu.com/wsknet/
不匹配,带有结尾的/http://baidu.com/wsknete
不匹配
「~」修饰符:区分大小写的正则匹配
server {
server_name baidu.com;
location ~ ^/wsknet$ {
[…]
}
}
http://baidu.com/wsknet
匹配(完全匹配)http://baidu.com/WSKNET
不匹配,大小写敏感http://baidu.com/wsknet?param1¶m2
匹配http://baidu.com/wsknet/
不匹配,不能匹配正则表达式http://baidu.com/wsknete
不匹配,不能匹配正则表达式
「~*」不区分大小写的正则匹配
server {
server_name baidu.com;
location ~* ^/wsknet$ {
[…]
}
}
http://baidu.com/wsknet
匹配 (完全匹配)http://baidu.com/WSKNET
匹配 (大小写不敏感)http://baidu.com/wsknet?param1¶m2
匹配http://baidu.com/wsknet/
不匹配,不能匹配正则表达式http://baidu.com/wsknets
不匹配,不能匹配正则表达式- 「^~」修饰符:前缀匹配 如果该 location 是最佳的匹配,那么对于匹配这个 location 的字符串, 该修饰符不再进行正则表达式检测。注意,这不是一个正则表达式匹配,它的目的是优先于正则表达式的匹配
查找的顺序及优先级
当有多条 location 规则时,nginx 有一套比较复杂的规则,优先级如下:
-
精确匹配 =
-
前缀匹配 ^~(立刻停止后续的正则搜索)
-
按文件中顺序的正则匹配
或* -
匹配不带任何修饰的前缀匹配。
这个规则是这样的:
- 先精确匹配,没有则查找带有 ^~的前缀匹配,没有则进行正则匹配,最后才返回前缀匹配的结果(如果有的话)
Nginx的rewrite模块
rewrite模块即ngx_http_rewrite_module模块,主要功能是改写请求URI,是Nginx默认安装的模块。rewrite模块会根据PCRE正则匹配重写URI,然后发起内部跳转再匹配location
rewrite指令所执行的顺序如下:
- 首先在server上下文中依照顺序执行rewrite模块指令;
- 如果server中行了rewrite重写,那么以新URI发起内部跳转,直接匹配location,不会再执行server里的rewrite指令
- 新URI直接匹配location
- 如果匹配上某个location,那么其中的rewrite模块指令同样依照顺序执行
- 如果再次导致URI的rewrite,那么再一次进行内部跳转去匹配location,但跳转的总次数不能超过10次
rewrite
基本语法: rewrite regex replacement [flag]`
`上下文:server, location, if
regex是PCRE风格的,如果regex匹配URI,那么URI就会被替换成replacement,replacement 就是新的URI。如果rewrite同一个上下文中有多个这样的正则,匹配会依照rewrite指令出现的顺序先后依次进行下去,匹配到一个之后并不会终止,而是继续往下匹配,直到返回最后一个匹配上的为止。如果想要中止继续往下匹配,可以使用第三个参数flag。
如果新URI字符中有关于协议的任何东西,比如http://
或者https://
等,进一步的处理就终止了
-
flag 参数值:
-
last:如果有last参数,那么停止处理任何rewrite相关的指令,立即用替换后的新URI开始下一轮的location匹配
server { listen 80; server_name baidu.com; location ^~ /wsknet { rewrite ^/wsknet/(.*) /test/$1 last; root /home/test; } location ^~ /test { return 200 "hello world"; } }
#curl http://baidu.com/wsknet/index.html => http://baidu.com/test/index.html => hello world
url由重写前的
http://baidu.com/wsknet/index.html
变为
http://baidu.com/test/index.html
-
重新进行location匹配后,匹配到第二个location条件,所以请求url得到的响应是hello wold
在配置rewrite last时,请求跳出当前location,进入server块,重新进行location匹配,超过10次匹配不到报500错误。客户端的url不变
- break: 停止处理任何rewrite的相关指令。如果出现在location里面,那么所有后面的rewrite模块指令都不会再执行,也不发起内部重定向,而是直接用新的URI进一步处理请求。
server {
listen 80;
server_name baidu.com
location ^~ /wsknet {
rewrite ^/wsknet/(.*) /test/$1 break;
root /home/test;
}
location ^~ /test {
return 200 "hello world";
}
}
#curl -s http://baidu.com/wsknet/index.html => test
#curl -s http://baidu.com/test/index.html => test
url由重写前的http://baidu.com/wsknet/index.html
变为http://baidu.com/test/index.html
,nginx按照重写后的url进行资源匹配,匹配到的资源文件是/home/test/index.html,所以请求url得到的响应就是/home/test/index.html文件中的内容:test。
配置rewrite break时,请求不会跳出当前location,但资源匹配会按照重写后的url进行,如果location里面配置的是proxy_pass到后端,后端服务器收到的请求url也会是重写后的url。客户端的url不变。
last的break的相同点在于,立即停止执行所有当前上下文的rewrite模块指令;不同点在于last参数接着用新的URI马上搜寻新的location,而break不会搜寻新的location,直接用这个新的URI来处理请求,这样能避免重复rewite。因此,在server上下文中使用last,而在location上下文中使用break。
-
rewrite在实际开发中的示例:
location /club { rewrite /club(.*) $1 break; # $1表示路径中正则表达式匹配的第一个参数 proxy_pass http://ip; }
curl ip/club/mongodb/version #这里的/mongodb/version便是匹配到的$1
result-> http://ip/mongodb/version
适配PC与移动环境
-
当用户从移动端打开PC端的场景时,将自动跳转至移动端wsknet.com,本质上是Nginx可以通过内置变量$http_user_agent,获取到请求客户端的userAgent,从而知道当前用户当前终端是移动端还是PC,进而重定向到H5站还是PC站
server { location / { //移动、pc设备agent获取 if ($http_user_agent ~* '(Android|baiduOS|iPhone)') { set $mobile_request '1'; } if ($mobile_request = '1') { rewrite ^.+ http://wsknet.com; } } }
Nginx配置https
# 配置监听 80 端口的服务器,用于 HTTP 到 HTTPS 的重定向
server {
listen 80; # 监听端口 80
server_name www.xxx.com; # 服务器名称
return 301 https://$server_name$request_uri; # 重定向到 HTTPS
}
# 配置监听 443 端口的服务器,启用 SSL
server {
listen 443 ssl; # 监听端口 443,启用 SSL
server_name www.xxx.com; # 服务器名称
ssl_certificate /etc/nginx/ssl/www.xxx.com.pem; # SSL 证书的路径
ssl_certificate_key /etc/nginx/ssl/www.xxx.com.key; # SSL 证书密钥的路径
ssl_session_timeout 10m; # SSL 会话超时设置
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; # 加密套件
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # 启用的 SSL 协议
ssl_prefer_server_ciphers on; # 优先使用服务器的加密套件
location / {
root /project/xxx; # 网站根目录
index index.html index.htm index.md; # 默认页面
try_files $uri $uri/ /index.html; # 尝试查找请求的文件,如果找不到则返回 index.html
}
}
nginx 端口映射多个应用
- 几个单页应用同时需要部署在同一台电脑上,并且都需要占用80或者443端口,可以采用以下的方式
server {
listen 80;
root /root/test; #baidu服务器目录;
location ^~ /a/{
try_files $uri /a/index.html; #如果找不到文件,就返回 /toot/test/a/index.html
}
location ^~ /b/{
try_files $uri /b/index.html; #如果找不到文件,就返回 /toot/test/b/index.html
}
}
Nginx 负载均衡配置
# 定义一个名为 my_upstream 的后端服务器组
upstream my_upstream {
server http://localhost:9001; # 后端服务器 1
server http://localhost:9002; # 后端服务器 2
server http://localhost:9003; # 后端服务器 3
}
# 配置监听 9000 端口的服务器
server {
listen 9000; # 监听端口
server_name test.com; # 服务器名称
location / {
proxy_pass my_upstream; # 将请求转发到 my_upstream
proxy_set_header Host $proxy_host; # 设置 Host 头
proxy_set_header X-Real-IP $remote_addr; # 传递真实客户端 IP
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 传递转发的 IP
}
}
Nginx中的URI变量
Nginx支持多个与URI相关的变量,这些变量可用于条件判断和重定向:
$uri:当前URI
$request_uri:包含请求参数的原始URI
$args:请求参数
$remote_addr:客户端IP地址
在nginx中有几个关于uri的变量,包括$uri $request_uri $document_uri,
它们的区别 :
$args #这个变量等于请求行中的参数。
$content_length #请求头中的Content-length字段。
$content_type #请求头中的Content-Type字段。
$document_root #当前请求在root指令中指定的值。
$host #请求主机头字段,否则为服务器名称。
$http_user_agent #客户端agent信息
$http_cookie #客户端cookie信息
$limit_rate #这个变量可以限制连接速率。
$request_body_file #客户端请求主体信息的临时文件名。
$request_method #客户端请求的动作,通常为GET或POST。
$remote_addr #客户端的IP地址。
$remote_port #客户端的端口。
$remote_user #已经经过Auth Basic Module验证的用户名。
$request_filename #当前请求的文件路径,由root或alias指令与URI请求生成。
$query_string #与$args相同。
$scheme #HTTP方法(如http,https)。
$server_protocol #请求使用的协议,通常是HTTP/1.0或HTTP/1.1。
$server_addr #服务器地址,在完成一次系统调用后可以确定这个值。
$server_name #服务器名称。
$server_port #请求到达服务器的端口号。
$request_uri #包含请求参数的原始URI,不包含主机名,如:”/foo/bar.php?arg=baz”。
$uri #不带请求参数的当前URI,$uri不包含主机名,如”/foo/bar.html”。
$document_uri #与$uri相同。
总结
Nginx 是强大的反向代理服务器,适合部署前端应用程序。通过合理配置,可以提高应用的性能、安全性和可扩展性。
参考:
nginx中如何设置gzip: https://www.cnblogs.com/Renyi-Fan/p/11047490.html
http://blog.sina.com.cn/s/articlelist_1834459124_0_1.html
https://openresty.org/download/agentzh-nginx-tutorials-zhcn.html#02-NginxDirectiveExecOrder01
https://juejin.cn/post/7196859948554715195