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` 3. `pnpm run build:antdv-next`
4. 将 `apps/web-antdv-next/dist` 原子发布到 Nginx 挂载的 Admin 静态目录 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', selfId: '10001',
}, },
container: { container: {
id: 'container-1',
name: 'kt-qqbot-napcat-10001',
webuiStatus: 'online' as const, webuiStatus: 'online' as const,
}, },
expiresAt: 1_782_000_000, expiresAt: 1_782_000_000,

View File

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

View File

@ -12,6 +12,15 @@ const accountRoot = resolve(
const readAccountSource = (relativePath: string) => const readAccountSource = (relativePath: string) =>
readFileSync(resolve(accountRoot, relativePath), 'utf8'); 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. * 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('hideInMenu: true');
expect(source).toContain("activePath: '/qqbot/account'"); 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>
<div class="qqbot-napcat-webui__meta"> <div class="qqbot-napcat-webui__meta">
<span>{session.container.value?.name || 'NapCat Gateway'}</span> <span>NapCat WebUI</span>
{expiresAtText.value ? ( {expiresAtText.value ? (
<span>{expiresAtText.value}</span> <span>{expiresAtText.value}</span>
) : null} ) : null}

View File

@ -148,8 +148,6 @@ function createSessionFixture(overrides = {}) {
selfId: '10001', selfId: '10001',
}, },
container: { container: {
id: 'container-1',
name: 'kt-qqbot-napcat-10001',
webuiStatus: 'online' as const, webuiStatus: 'online' as const,
}, },
expiresAt: new Date('2026-06-24T15:30:00+08:00').getTime(), 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/', '/qqbot/napcat/webui/session/session-1/',
); );
expect(wrapper.text()).toContain('主账号10001'); 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 () => { 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', target: 'http://localhost:48085',
ws: true, 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; 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)$ { location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y; expires 1y;
add_header Cache-Control "public, immutable"; add_header Cache-Control "public, immutable";