二级目录部署
本文介绍卷王问卷系统如何配置二级目录部署,适用于需要在域名下的子路径部署系统的场景。
应用场景
二级目录部署适用于以下场景:
- 共享域名资源,在同一域名下部署多个应用
- 企业内部统一门户,需要在子路径下访问问卷系统
- 反向代理环境,通过路径区分不同的后端服务
- CDN 或负载均衡器配置,需要基于路径进行路由
前端代码修改
获取二级目录版本
二级目录版本分支已单独推送到源码仓库,可通过以下方式获取:

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

配置说明:
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;
}
}
配置说明
关键配置点解析:
- 静态文件路径 (
root/alias): 分别指向dist/public和dist/admin - 二级目录名称:
/survey需与前端构建变量SK_BASE_PATH保持一致 - 静态资源前缀: public 使用
/survey/pub/,admin 使用/survey/adm/ - 后端服务端口: 根据实际后端部署情况修改端口号
- 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。
关键配置点
-
总行代理转发:
location /survey/匹配带/survey/前缀的请求proxy_pass http://b.com:58001转发时保留/survey前缀/captcha、/admin-api、/files默认不加二级目录前缀,也需要单独转发
-
分行服务配置:
- 监听端口
58001对应总行转发的目标端口 server_name使用总行域名,确保 Host 头正确- 前端项目按
/survey二级目录构建,确保/survey/pub/与/survey/adm/资源可访问
- 监听端口
-
访问路径示例:
- 用户访问:
https://a.com/survey/ - 总行转发:
http://b.com:58001/survey/ - 分行响应:返回前端首页
- 用户访问:
注意事项:
- 确保分行服务器的防火墙允许总行服务器访问 58001 端口
- 网络连通性测试:总行服务器能正常访问
b.com:58001 - 日志监控:建议在两端都启用访问日志,便于问题排查
通过以上完善的配置和说明,您可以顺利完成卷王问卷系统的二级目录部署。