Merge pull request #189 from Autumn-27/fix/sse-same-origin

fix(web): SSE 活动流默认同源,修复反代部署连不上 :8787
This commit is contained in:
Autumn authored and GitHub committed 2026-10-03 08:10:35 +08:00
commit d0033724a6
2 files changed
+48 -9

No files matched your search

+29
View File
@@ -222,6 +222,35 @@ CGO_ENABLED=0 go build -tags embedui -o artex ./cmd/artex
**常用参数**:`./start.sh -addr :8787 -proxy :8788`(`-addr` 前端+API,`-proxy` 流量录制代理)。启动脚本会把参数原样透传给 `artex`。
### 反向代理部署(HTTPS / 只开放 443)
前端和 API/SSE 都由同一个后端端口(默认 `:8787`)提供,实时活动流默认走**同源**地址,因此**无需配置 `NEXT_PUBLIC_SSE_BASE`**,公网只开放 443、把 8787 留在内网即可。
SSE 是长连接 + 持续推送,反代**必须关闭缓冲**,否则浏览器能连上却收不到事件(表现为活动流一直转圈)。Nginx 示例:
```nginx
server {
listen 443 ssl;
server_name your.domain.com;
# ssl_certificate / ssl_certificate_key ...
location / {
proxy_pass http://127.0.0.1:8787;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
# SSE 关键项:关缓冲、长超时、HTTP/1.1
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 3600s;
proxy_http_version 1.1;
proxy_set_header Connection "";
}
}
```
> 仅当 SSE 需要走与页面不同的来源(如独立子域)时,才在**构建期**设置 `NEXT_PUBLIC_SSE_BASE`(该变量在 `next build` 时固化进静态包,容器运行时再设无效)。
---
+19 -9
View File
@@ -146,14 +146,22 @@ export async function http<T>(path: string, init?: RequestInit): Promise<T> {
return r.json();
}
// sseUrl builds a URL for Server-Sent Events streams. SSE must NOT go through the
// Next.js dev `/api` rewrite: that proxy buffers the streamed response, so event
// frames never reach the browser (the EventSource opens but receives 0 messages).
// We therefore connect straight to the Go backend, whose CORS is open. Override
// with NEXT_PUBLIC_SSE_BASE; set it to "" to force same-origin (e.g. behind a
// production reverse proxy that flushes SSE correctly).
// Token is appended as ?token= because SSE bypasses the Next.js proxy and the
// browser does not send cookies cross-port.
// sseUrl builds a URL for Server-Sent Events streams.
//
// Production (static export / Docker): the Go backend serves the web UI *and* the
// SSE streams on the same port, so we default to a same-origin (relative) URL.
// This is what makes reverse-proxy deploys work: a page loaded from
// https://<domain>/ connects to https://<domain>/api/..., which the proxy forwards
// to the backend — no need to expose :8787 publicly. Hardcoding :8787 here used to
// break exactly that (https://<domain>:8787/... is unreachable when only 443 is open).
//
// Dev (next dev): SSE must NOT go through the Next.js `/api` rewrite — that proxy
// buffers the streamed response, so event frames never reach the browser (the
// EventSource opens but receives 0 messages). So in dev only we connect straight
// to the Go backend on :8787, whose CORS is open.
//
// Override either default with NEXT_PUBLIC_SSE_BASE (set it to "" to force same-origin).
// Token is appended as ?token= because SSE can't carry cookies cross-origin.
// mockReport returns a canned Markdown report for the demo.
function mockReport(_task?: string): string {
return `# ARTEX 渗透测试报告 — Acme Corp
@@ -180,7 +188,9 @@ function mockReport(_task?: string): string {
export function sseUrl(path: string): string {
const base =
process.env.NEXT_PUBLIC_SSE_BASE ??
(typeof window !== "undefined" ? `${window.location.protocol}//${window.location.hostname}:8787` : "");
(process.env.NODE_ENV !== "production" && typeof window !== "undefined"
? `${window.location.protocol}//${window.location.hostname}:8787`
: "");
const token = getToken();
const sep = path.includes("?") ? "&" : "?";
return token ? `${base}${path}${sep}token=${encodeURIComponent(token)}` : `${base}${path}`;