Nginx 难点攻克

汇聚各个时间段,关于Nginx的一些难点问题,他们掌握之后又很容易忘记,全部汇总在这里

1. 部署静态项目- 前端 assetsPublicPath 与 后端 context-path 相同;

配置思路:因为 Vue 项目打包之后 只有 static 和 index.html 两个顶级路由,所以只要把两个顶级路由配置给静态文件即可,其他的全部转发到后端。
配置缺陷:前端只能以 Hash 路由访问,不支持 history 路由

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
server {
listen 81;

# 解决静态404,重定向
location = /train-web/ {
root /usr/share/nginx/html/;
try_files $uri /train-web/index.html;
}

# 配置 static 顶级路由
location /train-web/static/ {
root /usr/share/nginx/html/;
}

# 配置 index.html 顶级路由
location /train-web/index.html {
root /usr/share/nginx/html/;
}

# 其余请求全部转发后端
location /train-web/ {
proxy_pass http://192.168.2.99:8070/train-web/;
}

}

2. 配置反向代理 - 代理 PublicPath 与 被代理服务的 PublicPath 不一致时

配置思路:不一致问题主要使用 rewrite 重写解决,但是内部js请求url 还是原来的 PublicPath 可以通过判断 $http_referer 做反响代理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
location = /plex {
rewrite ^/(.*)$ $1/ permanent;
}
location = /plex/ {
rewrite ^/(.*)$ index.html permanent;
}
location ^~ /plex/ {
rewrite ^/plex/(.+)$ /web/$1 break;
proxy_pass http://127.0.0.1:32400;
}
location ^~ /web/ {
if ($http_referer ~ ^https?://.+?/plex/.+) {
proxy_pass http://127.0.0.1:32400;
}
}

3. 文件上传被nginx反向代理后,后端无法立即接收到请求,无法实时读取文件流

问题说明
浏览器上传文件到 springboot 后端项目时,在spring的过滤器中能立即接收到客户端的请求,然后从流中读取文件信息。但是如果经过nginx proxy_pass 反向代理后,浏览器上传文件经过了nginx的转发,这个时候spring的过滤器中不能立即接收到浏览器请求,需要等待客户端把文件全部发送完毕才能接收到请求。

问题解决
使用proxy_request_bufferingproxy_buffering指令来禁用或修改Nginx的缓冲行为。

1
2
proxy_request_buffering off;
proxy_buffering off;

这将禁用Nginx对客户端请求和响应的缓冲,使得请求能够立即传递给后端的Spring Boot应用程序。这样,Spring的过滤器就能够立即接收到客户端的请求,并从流中读取文件信息。

4. add_header 导致有两个 Content-Type 问题

问题说明

1
2
3
4
5
6
7
8
9

server {
listen 80;
server_name ip.scwang90.cn;

add_header Content-Type "plain/text; charset=utf8";
return 200 $remote_addr;
}

上面的配置,在请求时返回结果有两个 Content-Type 如下:

1
2
3
4
5
6
7
8
9
10
11
12
root@lgs:~/projects/nginx# curl -i http://ip.scwang90.cn/
HTTP/1.1 200 OK
Server: nginx/1.23.3
Date: Mon, 15 Apr 2024 03:08:03 GMT
Content-Type: application/octet-stream
Content-Length: 12
Connection: keep-alive
Content-Type: plain/text; charset=utf8

185.55.21.50
root@lgs:~/projects/nginx#

可以看到,返回的 Header 中有两个 Content-Type:

1
2
3
4

Content-Type: application/octet-stream
Content-Type: plain/text; charset=utf8

问题解决

去除 add_header 使用 default_type 如下:

1
2
3
4
5
6
7
8
9

server {
listen 80;
server_name ip.scwang90.cn;

default_type 'text/plain; charset=utf-8';
return 200 $remote_addr;
}

访问结果:

1
2
3
4
5
6
7
8
9
10
11
root@lgs:~/projects/nginx# curl -i http://ip.scwang90.cn/
HTTP/1.1 200 OK
Server: nginx/1.23.3
Date: Mon, 15 Apr 2024 03:28:22 GMT
Content-Type: text/plain; charset=utf-8
Content-Length: 12
Connection: keep-alive

185.55.21.50
root@lgs:~/projects/nginx#

问题解决,default_type 告诉 Nginx,当需要为响应设置一个默认的 Content-Type 时,应该使用 text/plain 类型,并带有 charset=utf-8 的字符集。所以 Nginx 使用了 default_type 的值。

5. vue history模式 部署在服务器端的nginx配置 (非根目录)

vue history需要nginx或者其他方式配置一下才可正确访问,否则路由跳转之后刷新一下便会404 具体原因vue-router官网有说明,在此不多说

最近遇到的问题是上了一个小的项目,需要放在更深层次的目录下,上到测试环境 做了官网提到的nginx配置发现不行,之后查阅了一些博客资料,发现都没有一个特别好的方案。最终,我的解决方案如下

nginx配置如下

1
2
3
4
5
6
7
8
9
10
server {
listen 443 ;
server_name m;

root html/mobile;
location / {
index index.html index.htm;
try_files $uri $uri/ /auth/index.html;
}
}

vue router 配置

1
2
3
4
5
6
// 路由配置
const RouterConfig = {
base: "/auth/",
mode: 'history',
routes: routers
};

该项目是用的vue-cli2 所以只需要修改config 里面的index.js的build部分

webpack 配置修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
build: {
// Template for index.html
index: path.resolve(__dirname, '../dist/auth/index.html'),
// Paths
assetsRoot: path.resolve(__dirname, '../dist'),
assetsSubDirectory: 'auth/static',
assetsPublicPath: '/',
/**
* Source Maps
*/
productionSourceMap: false,
devtool: '#source-map',
productionGzip: false,
productionGzipExtensions: ['js', 'css'],
bundleAnalyzerReport: process.env.npm_config_report
}

最终项目地址为 m.xxx.com/auth/