又到了前端啥都要学系列

Nginx定义 & 优点

Nginx (engine x) 是一个轻量级、高性能的HTTP、反向代理服务器,同时也是一个通用代理服务器(TCP/UDP/IMAP/POP3/SMTP)

它具有高性能,占用内存少,并发能力强的优点,最大可以支持50000个并发连接数

Nginx的常用命令

安装

当然,在开始使用之前,你需要先下载Nginx

官网链接:http://nginx.org/en/download.html

下载完毕后,解压即可使用,目录是这样的

image-20230422105838529

目录树如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
├── client_body_temp
├── conf # Nginx所有配置文件的目录
│ ├── fastcgi.conf # fastcgi相关参数的配置文件
│ ├── fastcgi.conf.default # fastcgi.conf的原始备份文件
│ ├── fastcgi_params # fastcgi的参数文件
│ ├── fastcgi_params.default
│ ├── koi-utf
│ ├── koi-win
│ ├── mime.types # 媒体类型
│ ├── mime.types.default
│ ├── nginx.conf # Nginx主配置文件
│ ├── nginx.conf.default
│ ├── scgi_params # scgi相关参数文件
│ ├── scgi_params.default
│ ├── uwsgi_params # uwsgi相关参数文件
│ ├── uwsgi_params.default
│ └── win-utf
├── fastcgi_temp # fastcgi临时数据目录
├── html # Nginx默认站点目录
│ ├── 50x.html # 错误页面优雅替代显示文件,例如当出现502错误时会调用此页面
│ └── index.html # 默认的首页文件
├── logs # Nginx日志目录
│ ├── access.log # 访问日志文件
│ ├── error.log # 错误日志文件
│ └── nginx.pid # pid文件,Nginx进程启动后,会把所有进程的ID号写到此文件
├── proxy_temp # 临时目录
├── sbin # Nginx命令目录
│ └── nginx # Nginx的启动命令
├── scgi_temp # 临时目录
└── uwsgi_temp # 临时目录

常用命令

PS:默认情况下,你需要在目录位置对应的控制台下才能运行这些命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# 启动 (启动效果可以访问http://localhost:80查看)
$ nginx # 会一直阻塞cmd窗口
$ start nginx # 打印日志后可以退出

# 查看版本(-v换成-V可以查看更详细的版本信息)
$ nginx -v
nginx version: nginx/1.24.0

# 检查配置语法是否正确
$ nginx -t
nginx: the configuration file G:\program\nginx-1.24.0/conf/nginx.conf syntax is ok
nginx: configuration file G:\program\nginx-1.24.0/conf/nginx.conf test is successful

# 重新载入Nginx
# 当配置信息修改时,使用这个命令重新加载nginx配置
$ nginx -s reload

# 停止nginx
# PS:-s是代表向nginx进程发送通知的意思
$ nginx -s stop # 强制停止nginx
$ nginx -s quit # 有序停止nginx

# 查看全部命令
$ nginx -h
nginx version: nginx/1.24.0
Usage: nginx [-?hvVtTq] [-s signal] [-p prefix]
[-e filename] [-c filename] [-g directives]
Options:
-?,-h : this help
-v : show version and exit
-V : show version and configure options then exit
-t : test configuration and exit
-T : test configuration, dump it and exit
-q : suppress non-error messages during configuration testing
-s signal : send signal to a master process: stop, quit, reopen, reload
-p prefix : set prefix path (default: NONE)
-e filename : set error log file (default: logs/error.log)
-c filename : set configuration file (default: conf/nginx.conf)
-g directives : set global directives out of configuration file

Nginx配置

这里循序渐进地对Nginx配置做一些简单的介绍

从默认的Nginx文件开始

nginx的默认配置文件nginx.conf在安装目录conf文件夹下

在移除所有Nginx注释后,我们可以得到以下配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 全局块
worker_processes 1;

# event块
events {
worker_connections 1024;
}

# http块
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
# server块
server {
listen 80;
server_name localhost;

# location块
location / {
root html;
index index.html index.htm;
}

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

其中,每个块的作用如下,这里我们重点关注serverlocation块即可

  • 全局块:nginx全局块是指nginx配置文件中的最外层块,它可以包含多个指令和其他块,用于定义全局的配置和行为,
  • events块:主要用于配置事件驱动模型和连接数限制。
  • http块:用于定义HTTP全局配置。处理代理,缓存,日志定义等绝大多数功能和第三方模块的配置,比如文件引入,mime-type定义,日志自定义,是否使用sendfile传输文件,连接超时时间,单连接请求数等。
  • server块:配置虚拟主机的相关参数。
  • location块:定义一个URI或者URI模式对应的请求处理规则。

location块的处理规则

Location的具体语法为

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

例子如下

PS:不知道为什么,匹配大小写的设置无法生效,可能是window的nginx有问题?或者是nginx新版本有什么问题…以后再看看吧

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
server {
listen 9998; # 监听9998端口
server_name localhost; # 监听的服务器名字

# = 表示精确匹配
location = /getUser {
add_header Content-Type "application/json";
return 200 "{id: 1, age: 16}";
}

# ~表示区分大小写的正则匹配
location ~ ^/getData$ {
add_header Content-Type "application/json";
return 200 "{id: 2, age: 16}";
}

# ~*表示不区分大小写的正则匹配
location ~* ^/list$ {
add_header Content-Type "application/json";
return 200 "[1,2,3]";
}

# ^~表示url以某个字符串开头
# 当访问http://localhost:9998/img/1.jpg时,可以访问到静态文件服务器下的图片
location ^~ /img/ { # 指定匹配的路径
root static/; # 指定web服务器的根目录
index index.html; # 指定默认的主页文件名
}
}

server {
listen 9997;
server_name localhost;
# 表示通用匹配
# 当访问http://localhost:9998/css/index.css时,可以访问到静态文件服务器下的样式文件
location /css {
root static/;
index index.html;
}
# 表示通用匹配
location / {
add_header Content-Type "text/plain";
return 200 "Hello World";
}
}

相对简单,用到时再查就完事

这里值的顺便一提的是,如果有多个location规则可以命中,那么会遵循一定的优先级配置来进行返回。

  • 检查使用前缀字符串(也就是通用匹配开头)的 locations,在使用前缀字符串的 locations 中选择最长匹配的,并将结果进行储存
  • 如果匹配到符合带有 = 修饰符的 URI,则立刻停止匹配
  • 如果符合带有 ^~ 修饰符的 URI,则也立刻停止匹配。
  • 然后按照定义文件的顺序,检查正则表达式(也就是前面带~*~ 修饰符的),匹配到就停止
  • 当正则表达式匹配不到的时候,使用之前储存的前缀字符串

一些简单的Nginx模板

加载自定义配置

这里我们用include指令加载nginx的相关配置

1
2
3
4
http {
include mime.types;
include config/*.conf; # 加载nginx/conf/config目录下的所有配置文件
}

启动一个静态网站服务

nginx/conf/config目录下新建一个static-server.conf文件,然后加上以下配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 开启一个本地代理服务器
server {
listen 9999; # 监听9999端口
server_name localhost; # 监听的服务器名字

# 开启gzip压缩
gzip on;
gzip_min_length 1k; # 最小压缩单位
gzip_types application/javascript; # 取自响应头Content-Type
gzip_static on; # 启用预先压缩的Gzip文件(也就是搜索同目录下的.gz文件返回)

location / { # 指定匹配的路径
root static/; # 指定web服务器的根目录
index index.html; # 指定默认的主页文件名
}
}

然后,在/static目录下,加上一些文件

image-20230425174325432

调用nginx -s reload重启配置后,就可以通过访问localhost:9999查看效果了

image-20230426175239196

单页应用路由处理

总所周知,如果你的路由使用了history模式,那么在访问localhost:8080/about这种链接时,会返回404

原因是nginx会把这个连接当成一个文件去处理(你可以在dist目录下加一个about文件来验证),而nginx找不到这个文件,所以就会返回404

1
2
3
4
5
6
7
8
9
10
11
# 开启一个本地代理服务器
server {
listen 9996; # 监听9996端口
server_name localhost; # 监听的服务器名字

location / { # 指定匹配的路径
root dist/; # 指定web服务器的根目录
index index.html; # 指定默认的主页文件名
try_files $uri $uri/ /index.html; # 将所有路由请求重定向到Vue应用的入口文件(index.html)
}
}

我们仅需在静态网站的基础上,添加一行try_files $uri $uri/ /index.html配置即可,这样我们就可以将路由请求重定向回index.html了(但注意,不要在目录下存放和路由同名的文件,不然的话,就会访问那个同名的文件)。

image-20230505161624645

开启防盗链

只要在nginx中加入以下的配置即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 开启一个本地代理服务器
server {
listen 9999; # 监听9999端口
server_name localhost; # 监听的服务器名字

# ...其他配置省略

# 防盗链配置
location ~* .*\.(gif|jpg|png)$ {
root static/;
valid_referers localhost; # 仅限localhost访问
if ($invalid_referer) {
# 配置返回403
# return 403;
# 配置:重定向请求
rewrite ^/ https://s2.loli.net/2023/04/25/HyDgp25ZsVxwJ83.png;
break;
}
}
}

负载均衡

平均将请求转发到两台服务器上

1
2
3
4
5
6
7
8
9
10
11
12
upstream webapp {
server localhost:9996 weight=1;
server localhost:9999 weight=1;
random two least_conn;
}

server {
listen 9995;
location / {
proxy_pass http://webapp;
}
}

跨域

跨域的配置非常简单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
server {
listen 8070;
location / {
# 允许跨域的请求,可以自定义变量$http_origin,*表示所有, always表示所有情况下都返回
add_header 'Access-Control-Allow-Origin' * always;
# 允许携带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;
}
# 对localhost:8070所有的请求都会被转发到https://server.com
proxy_pass https://server.com;
}
}

请求的时候使用以下代码

1
2
3
4
5
6
7
8
let baseUrl = IsDev ? "http://localhost:8070/" : `https://server.com`;	// 根据环境选择前缀
let instance = axios.createInstance({
baseUrl: baseUrl
});
(async function () {
let data = await instance.get("/data");
console.log('data', data);
})()

参考

前端仔也需要懂的nginx内容:https://juejin.cn/post/7007346707767754765

Nginx location匹配规则:https://www.cnblogs.com/woshimrf/p/nginx-config-location.html

Nginx配置文件介绍:https://zhuanlan.zhihu.com/p/396032376

nginx.conf配置文件详解:https://juejin.cn/post/6844903741678698510

nginx反向代理解决跨域问题:https://juejin.cn/post/6995374680114741279

nginx一网打尽:https://juejin.cn/post/7112826654291918855#heading-13