跳到主要内容

二级目录部署

本文介绍卷王问卷系统如何配置二级目录部署,适用于需要在域名下的子路径部署系统的场景。

应用场景

二级目录部署适用于以下场景:

  • 共享域名资源,在同一域名下部署多个应用
  • 企业内部统一门户,需要在子路径下访问问卷系统
  • 反向代理环境,通过路径区分不同的后端服务
  • CDN 或负载均衡器配置,需要基于路径进行路由

前端代码修改

获取二级目录版本

二级目录版本分支已单独推送到源码仓库,可通过以下方式获取:

1698819400965

配置二级目录路径

默认的二级目录名称是 /survey。如需改为其他名称,推荐通过构建变量重新构建前端:

1698819616306

配置说明:

SK_BASE_PATH=/survey pnpm build

重要提示:

  • 页面路由前缀为 /survey/
  • public 入口静态资源前缀为 /survey/pub/
  • admin 入口静态资源前缀为 /survey/adm/
  • 路径必须以 / 开头和结尾
  • 修改后需要重新构建前端项目

Nginx 配置

基础配置

正式部署的 nginx 配置文件如下,重点参见下面配置文件中的关键配置点:

map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}

server {
listen 80;
index index.html;
client_max_body_size 30m;

# 将 /usr/local/html/dist 替换为前端构建产物 dist 的实际绝对路径。
location = /survey {
return 301 /survey/;
}

location = /survey/pub/index.html {
root /usr/local/html/dist/public;
etag off;
add_header Cache-Control "no-cache, no-store, must-revalidate" always;
add_header Pragma "no-cache" always;
add_header Expires "0" always;
add_header X-Version $date_gmt always;
add_header Vary "Accept-Encoding" always;
try_files /index.html =404;
}

location = /survey/adm/index.html {
root /usr/local/html/dist/admin;
etag off;
add_header Cache-Control "no-cache, no-store, must-revalidate" always;
add_header Pragma "no-cache" always;
add_header Expires "0" always;
add_header X-Version $date_gmt always;
add_header Vary "Accept-Encoding" always;
try_files /index.html =404;
}

location ^~ /survey/pub/ {
alias /usr/local/html/dist/public/;
expires 1y;
add_header Cache-Control "public, max-age=31536000, immutable";
add_header Vary "Accept-Encoding" always;
try_files $uri =404;
}

location ^~ /survey/adm/ {
alias /usr/local/html/dist/admin/;
expires 1y;
add_header Cache-Control "public, max-age=31536000, immutable";
add_header Vary "Accept-Encoding" always;
try_files $uri =404;
}

# 答题、练习、公开查询、兑换页面走 public 入口。
location ~ ^/survey/(e|s|t|q|redeem)(/|$) {
root /usr/local/html/dist/public;
add_header Cache-Control "no-cache, no-store, must-revalidate" always;
add_header Pragma "no-cache" always;
add_header Expires "0" always;
add_header X-Version $date_gmt always;
add_header Vary "Accept-Encoding" always;
try_files /index.html =404;
}

# 登录注册绑定同时被答题和后台使用,线上优先返回 public 入口。
location ~ ^/survey/user/(login|register|binding)/?$ {
root /usr/local/html/dist/public;
add_header Cache-Control "no-cache, no-store, must-revalidate" always;
add_header Pragma "no-cache" always;
add_header Expires "0" always;
add_header X-Version $date_gmt always;
add_header Vary "Accept-Encoding" always;
try_files /index.html =404;
}

# API 路径默认不加 /survey 前缀,和前端页面前缀分开。
location /captcha {
proxy_pass http://localhost:1991/captcha;
set_real_ip_from 0.0.0.0/0;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
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;
client_max_body_size 30m;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_send_timeout 1800;
proxy_read_timeout 1800;
proxy_connect_timeout 1800;
}

location /admin-api {
proxy_pass http://localhost:1991/admin-api;
proxy_buffering off;
proxy_cache off;
set_real_ip_from 0.0.0.0/0;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
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;
client_max_body_size 30m;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_send_timeout 1800;
proxy_read_timeout 1800;
proxy_connect_timeout 1800;
}

location /files {
proxy_pass http://localhost:1991/files;
set_real_ip_from 0.0.0.0/0;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
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;
client_max_body_size 30m;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_send_timeout 1800;
proxy_read_timeout 1800;
proxy_connect_timeout 1800;
}

location /health {
access_log off;
return 200 "healthy\n";
add_header Content-Type text/plain;
}

# 其它前端路由走后台入口。
location /survey/ {
root /usr/local/html/dist/admin;
add_header Cache-Control "no-cache, no-store, must-revalidate" always;
add_header Pragma "no-cache" always;
add_header Expires "0" always;
add_header X-Version $date_gmt always;
add_header Vary "Accept-Encoding" always;
try_files $uri $uri/ /index.html;
}
}

配置说明

关键配置点解析:

  1. 静态文件路径 (root/alias): 分别指向 dist/publicdist/admin
  2. 二级目录名称: /survey 需与前端构建变量 SK_BASE_PATH 保持一致
  3. 静态资源前缀: public 使用 /survey/pub/,admin 使用 /survey/adm/
  4. 后端服务端口: 根据实际后端部署情况修改端口号
  5. try_files: 确保前端路由正常工作,避免刷新页面时 404

常见场景

1. 内外网独立访问

使用场景:分离内外网访问,只允许外网访问答卷页面,管理页面仅限内网访问。当外网和内网使用不同的 nginx 时,可配置代理转发。

参考文档

2. 总行-分行架构部署

使用场景:总行提供统一域名访问,但问卷系统实际部署在分行服务器上。总行域名通过代理转发到分行服务器。

架构说明

  • 总行域名:a.com/survey
  • 分行服务器:b.com:58001
  • 前端项目配置:根目录部署(非二级目录)

总行 Nginx 配置

总行服务器上的 nginx 配置,负责将请求转发到分行:

server {
listen 8081;
server_name a.com;

# 将 /survey/ 路径的所有请求转发到分行服务器,并保留 /survey 前缀。
location /survey/ {
proxy_pass http://b.com:58001;
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;
}

# API 默认不加 /survey 前缀,也需要转发到分行。
location /captcha {
proxy_pass http://b.com:58001;
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 /admin-api {
proxy_pass http://b.com:58001;
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 /files {
proxy_pass http://b.com:58001;
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;
}
}

分行 Nginx 配置

分行服务器上的 nginx 配置,直接提供服务:

map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}

server {
listen 58001;
server_name a.com; # 使用总行域名
index index.html;
client_max_body_size 30m;

# 前端使用 SK_BASE_PATH=/survey 构建,dist 目录包含 public 和 admin。
location = /survey {
return 301 /survey/;
}

location = /survey/pub/index.html {
root /root/dist/public;
etag off;
add_header Cache-Control "no-cache, no-store, must-revalidate" always;
add_header Pragma "no-cache" always;
add_header Expires "0" always;
add_header X-Version $date_gmt always;
add_header Vary "Accept-Encoding" always;
try_files /index.html =404;
}

location = /survey/adm/index.html {
root /root/dist/admin;
etag off;
add_header Cache-Control "no-cache, no-store, must-revalidate" always;
add_header Pragma "no-cache" always;
add_header Expires "0" always;
add_header X-Version $date_gmt always;
add_header Vary "Accept-Encoding" always;
try_files /index.html =404;
}

location ^~ /survey/pub/ {
alias /root/dist/public/;
expires 1y;
add_header Cache-Control "public, max-age=31536000, immutable";
add_header Vary "Accept-Encoding" always;
try_files $uri =404;
}

location ^~ /survey/adm/ {
alias /root/dist/admin/;
expires 1y;
add_header Cache-Control "public, max-age=31536000, immutable";
add_header Vary "Accept-Encoding" always;
try_files $uri =404;
}

location ~ ^/survey/(e|s|t|q|redeem)(/|$) {
root /root/dist/public;
add_header Cache-Control "no-cache, no-store, must-revalidate" always;
add_header Pragma "no-cache" always;
add_header Expires "0" always;
add_header X-Version $date_gmt always;
add_header Vary "Accept-Encoding" always;
try_files /index.html =404;
}

location ~ ^/survey/user/(login|register|binding)/?$ {
root /root/dist/public;
add_header Cache-Control "no-cache, no-store, must-revalidate" always;
add_header Pragma "no-cache" always;
add_header Expires "0" always;
add_header X-Version $date_gmt always;
add_header Vary "Accept-Encoding" always;
try_files /index.html =404;
}

location /captcha {
proxy_pass http://localhost:48080/captcha;
set_real_ip_from 0.0.0.0/0;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
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;
client_max_body_size 30m;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_send_timeout 1800;
proxy_read_timeout 1800;
proxy_connect_timeout 1800;
}

location /admin-api {
proxy_pass http://localhost:48080/admin-api;
proxy_buffering off;
proxy_cache off;
set_real_ip_from 0.0.0.0/0;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
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;
client_max_body_size 30m;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_send_timeout 1800;
proxy_read_timeout 1800;
proxy_connect_timeout 1800;
}

location /files {
proxy_pass http://localhost:48080/files;
set_real_ip_from 0.0.0.0/0;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
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;
client_max_body_size 30m;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_send_timeout 1800;
proxy_read_timeout 1800;
proxy_connect_timeout 1800;
}

location /health {
access_log off;
return 200 "healthy\n";
add_header Content-Type text/plain;
}

location /survey/ {
root /root/dist/admin;
add_header Cache-Control "no-cache, no-store, must-revalidate" always;
add_header Pragma "no-cache" always;
add_header Expires "0" always;
add_header X-Version $date_gmt always;
add_header Vary "Accept-Encoding" always;
try_files $uri $uri/ /index.html;
}
}

前端配置说明

对于这种架构,前端仍按二级目录构建:SK_BASE_PATH=/survey pnpm build

关键配置点

  1. 总行代理转发

    • location /survey/ 匹配带 /survey/ 前缀的请求
    • proxy_pass http://b.com:58001 转发时保留 /survey 前缀
    • /captcha/admin-api/files 默认不加二级目录前缀,也需要单独转发
  2. 分行服务配置

    • 监听端口 58001 对应总行转发的目标端口
    • server_name 使用总行域名,确保 Host 头正确
    • 前端项目按 /survey 二级目录构建,确保 /survey/pub//survey/adm/ 资源可访问
  3. 访问路径示例

    • 用户访问:https://a.com/survey/
    • 总行转发:http://b.com:58001/survey/
    • 分行响应:返回前端首页

注意事项

  • 确保分行服务器的防火墙允许总行服务器访问 58001 端口
  • 网络连通性测试:总行服务器能正常访问 b.com:58001
  • 日志监控:建议在两端都启用访问日志,便于问题排查

通过以上完善的配置和说明,您可以顺利完成卷王问卷系统的二级目录部署。