fix: 暴露NapCat WebUI同源代理

This commit is contained in:
sunlei 2026-06-24 16:30:12 +08:00
parent 8795227c05
commit 8616f16383
8 changed files with 40 additions and 8 deletions

View File

@ -59,7 +59,7 @@ Jenkins 使用 `Jenkinsfile` 执行:
3. `pnpm run build:antdv-next`
4. 将 `apps/web-antdv-next/dist` 原子发布到 Nginx 挂载的 Admin 静态目录
Nginx 配置见 `deploy/nginx-admin.conf`,默认监听 `5999`,静态根目录为 `/usr/share/nginx/html/admin`,并将浏览器侧 `/api/*` 转发到后端 `192.168.31.224:48085`。配置保留 gzip、静态资源长缓存、入口 HTML 不缓存和 SPA 回退。
Nginx 配置见 `deploy/nginx-admin.conf`,默认监听 `5999`,静态根目录为 `/usr/share/nginx/html/admin`,并将浏览器侧 `/api/*` 转发到后端 `192.168.31.224:48085`,将 `/napcat-webui/*` 转发到 NapCat WebUI Gateway `192.168.31.224:48086`。配置保留 gzip、静态资源长缓存、入口 HTML 不缓存、WebUI WebSocket 转发和 SPA 回退。
## 提交规范

View File

@ -246,8 +246,6 @@ describe('napcat login display helpers', () => {
selfId: '10001',
},
container: {
id: 'container-1',
name: 'kt-qqbot-napcat-10001',
webuiStatus: 'online' as const,
},
expiresAt: 1_782_000_000,

View File

@ -31,8 +31,6 @@ export namespace QqbotNapcatApi {
}
export interface WebuiGatewaySessionContainer {
id: string;
name: string;
webuiStatus: 'offline' | 'online' | 'unknown';
}

View File

@ -12,6 +12,15 @@ const accountRoot = resolve(
const readAccountSource = (relativePath: string) =>
readFileSync(resolve(accountRoot, relativePath), 'utf8');
/**
* Reads repository-root files that define browser-facing deployment boundaries.
*
* @param relativePath - Repository-relative path to read.
* @returns Source text for boundary assertions.
*/
const readRepoSource = (relativePath: string) =>
readFileSync(resolve(cwd(), relativePath), 'utf8');
/**
* Reads QQBot router module source for route boundary assertions.
*/
@ -71,4 +80,15 @@ describe('qqbot account NapCat login view boundary', () => {
expect(source).toContain('hideInMenu: true');
expect(source).toContain("activePath: '/qqbot/account'");
});
it('exposes the NapCat WebUI gateway through the Admin same-origin dev and nginx routes', () => {
const viteSource = readRepoSource('apps/web-antdv-next/vite.config.mts');
const nginxSource = readRepoSource('deploy/nginx-admin.conf');
expect(viteSource).toContain("'/napcat-webui'");
expect(viteSource).toContain('http://localhost:48086');
expect(nginxSource).toContain('location ^~ /napcat-webui/');
expect(nginxSource).toContain('48086');
expect(nginxSource).toContain('proxy_http_version 1.1');
});
});

View File

@ -161,7 +161,7 @@ export default defineComponent({
</div>
<div class="qqbot-napcat-webui__meta">
<span>{session.container.value?.name || 'NapCat Gateway'}</span>
<span>NapCat WebUI</span>
{expiresAtText.value ? (
<span>{expiresAtText.value}</span>
) : null}

View File

@ -148,8 +148,6 @@ function createSessionFixture(overrides = {}) {
selfId: '10001',
},
container: {
id: 'container-1',
name: 'kt-qqbot-napcat-10001',
webuiStatus: 'online' as const,
},
expiresAt: new Date('2026-06-24T15:30:00+08:00').getTime(),
@ -193,6 +191,8 @@ describe('qqbot account NapCat WebUI page', () => {
'/qqbot/napcat/webui/session/session-1/',
);
expect(wrapper.text()).toContain('主账号10001');
expect(wrapper.text()).toContain('NapCat WebUI');
expect(wrapper.text()).not.toContain('kt-qqbot-napcat');
});
it('revokes the active session and pauses heartbeat on unmount', async () => {

View File

@ -13,6 +13,11 @@ const config = defineConfig(async () => {
target: 'http://localhost:48085',
ws: true,
},
'/napcat-webui': {
changeOrigin: true,
target: 'http://localhost:48086',
ws: true,
},
},
},
},

View File

@ -23,6 +23,17 @@ server {
proxy_set_header X-Forwarded-Proto $scheme;
}
location ^~ /napcat-webui/ {
proxy_pass http://192.168.31.224:48086/napcat-webui/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
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 ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";