Handle dev TrackerHub poll timeouts in proxy

This commit is contained in:
2026-05-07 00:50:27 +03:00
parent eadd42cacc
commit fb6c778d8b
2 changed files with 39 additions and 40 deletions
+33 -8
View File
@@ -10,7 +10,7 @@
* /* → localhost:8081 (Modern.js SSR + HMR)
*/
import express from "express";
import { createProxyMiddleware } from "http-proxy-middleware";
import { createProxyMiddleware, responseInterceptor } from "http-proxy-middleware";
import { HttpsProxyAgent } from "https-proxy-agent";
import { execFile, spawn } from "node:child_process";
import { resolve } from "node:path";
@@ -159,6 +159,25 @@ function normalizeTrackerCookie(cookie) {
return [...parts, "Path=/tracker/hub", "SameSite=Lax"].join("; ");
}
function applyTrackerCookieHeaders(proxyRes, res) {
const setCookie = proxyRes.headers["set-cookie"];
if (Array.isArray(setCookie)) {
res.setHeader("set-cookie", setCookie.map(normalizeTrackerCookie));
} else if (typeof setCookie === "string") {
res.setHeader("set-cookie", normalizeTrackerCookie(setCookie));
}
}
function isTrackerLongPollTimeout(proxyRes, req) {
const requestUrl = req.originalUrl ?? req.url ?? "";
return (
req.method === "GET" &&
(requestUrl.startsWith("/tracker/hub?id=") ||
requestUrl.startsWith("/hub?id=")) &&
proxyRes.statusCode === 504
);
}
// --- SignalR TrackerHub proxy ---
// Browser-direct localhost → platform.test.aeroflot.ru fails CORS. Keep the
// hub same-origin in development and let proxy-helper / gost route the
@@ -170,15 +189,21 @@ const trackerProxy = createProxyMiddleware({
ws: true,
logLevel: "warn",
pathRewrite: (path) => `/tracker${path}`,
selfHandleResponse: true,
on: {
proxyRes(proxyRes) {
const setCookie = proxyRes.headers["set-cookie"];
if (Array.isArray(setCookie)) {
proxyRes.headers["set-cookie"] = setCookie.map(normalizeTrackerCookie);
} else if (typeof setCookie === "string") {
proxyRes.headers["set-cookie"] = normalizeTrackerCookie(setCookie);
proxyRes: responseInterceptor(async (buffer, proxyRes, req, res) => {
applyTrackerCookieHeaders(proxyRes, res);
if (isTrackerLongPollTimeout(proxyRes, req)) {
console.warn(`Tracker long poll timed out upstream, returning empty 200 for ${req.originalUrl ?? req.url}`);
res.statusCode = 200;
res.statusMessage = "OK";
res.setHeader("content-type", "text/plain");
return "";
}
},
return buffer;
}),
},
...(SYSTEM_PROXY ? { agent: new HttpsProxyAgent(SYSTEM_PROXY) } : {}),
});
+6 -32
View File
@@ -224,8 +224,6 @@ export function _resetSharedConnections(): void {
// ---- Default builder (dynamic import) ----
const DEV_TRACKER_LONG_POLL_TIMEOUT_MS = 10000;
export function _shouldUseLongPollingForDevTrackerProxy(url: string): boolean {
try {
const parsed = new URL(url, "http://localhost");
@@ -243,39 +241,15 @@ async function defaultBuildConnection(
url: string,
delays: number[],
): Promise<HubConnectionLike> {
const {
DefaultHttpClient,
HttpClient,
HubConnectionBuilder,
HttpTransportType,
LogLevel,
NullLogger,
} = await import("@microsoft/signalr");
const { HubConnectionBuilder, HttpTransportType, LogLevel } = await import(
"@microsoft/signalr"
);
const builder = new HubConnectionBuilder();
const useDevTrackerLongPolling = _shouldUseLongPollingForDevTrackerProxy(url);
const withUrlOptions = useDevTrackerLongPolling
? {
transport: HttpTransportType.LongPolling,
httpClient: new (class extends HttpClient {
private readonly inner = new DefaultHttpClient(NullLogger.instance);
send(request: Parameters<InstanceType<typeof HttpClient>["send"]>[0]) {
if (request.method !== "GET") {
return this.inner.send(request);
}
return this.inner.send({
...request,
timeout: DEV_TRACKER_LONG_POLL_TIMEOUT_MS,
});
}
})(),
}
const withUrlOptions = _shouldUseLongPollingForDevTrackerProxy(url)
? { transport: HttpTransportType.LongPolling }
: undefined;
return (withUrlOptions
? builder.withUrl(url, withUrlOptions)
: builder.withUrl(url))
return (withUrlOptions ? builder.withUrl(url, withUrlOptions) : builder.withUrl(url))
.withAutomaticReconnect(delays)
// Suppress SignalR's internal console logging. The hub is optional
// (failures degrade to polling) and we already handle status via