diff --git a/src/views/StockOverview/components/FlexScreen/hooks/useRealtimeQuote.ts b/src/views/StockOverview/components/FlexScreen/hooks/useRealtimeQuote.ts index dfb69bfc..1167614a 100644 --- a/src/views/StockOverview/components/FlexScreen/hooks/useRealtimeQuote.ts +++ b/src/views/StockOverview/components/FlexScreen/hooks/useRealtimeQuote.ts @@ -402,59 +402,77 @@ export const useRealtimeQuote = (codes: string[] = []): UseRealtimeQuoteReturn = }, []); const createConnection = useCallback((exchange: Exchange) => { + // 检查是否是 HTTPS 页面尝试连接 ws://(Mixed Content) + const isHttps = typeof window !== 'undefined' && window.location.protocol === 'https:'; + const wsUrl = WS_CONFIG[exchange]; + const isInsecureWs = wsUrl.startsWith('ws://'); + + if (isHttps && isInsecureWs) { + logger.warn( + 'FlexScreen', + `${exchange} WebSocket 连接被跳过:HTTPS 页面无法连接不安全的 ws:// 端点` + ); + return; + } + if (wsRefs.current[exchange]) { wsRefs.current[exchange]!.close(); } - const ws = new WebSocket(WS_CONFIG[exchange]); - wsRefs.current[exchange] = ws; + try { + const ws = new WebSocket(wsUrl); + wsRefs.current[exchange] = ws; - ws.onopen = () => { - logger.info('FlexScreen', `${exchange} WebSocket 已连接`); - setConnected(prev => ({ ...prev, [exchange]: true })); + ws.onopen = () => { + logger.info('FlexScreen', `${exchange} WebSocket 已连接`); + setConnected(prev => ({ ...prev, [exchange]: true })); - if (exchange === 'SSE') { - const codes = Array.from(subscribedCodes.current.SSE); - if (codes.length > 0) { - ws.send(JSON.stringify({ - action: 'subscribe', - channels: ['stock', 'index'], - codes, - })); - } - } - - startHeartbeat(exchange); - }; - - ws.onmessage = (event: MessageEvent) => { - try { - const msg = JSON.parse(event.data); - handleMessage(exchange, msg); - } catch (e) { - logger.warn('FlexScreen', `${exchange} 消息解析失败`, e); - } - }; - - ws.onerror = (error: Event) => { - logger.error('FlexScreen', `${exchange} WebSocket 错误`, error); - }; - - ws.onclose = () => { - logger.info('FlexScreen', `${exchange} WebSocket 断开`); - setConnected(prev => ({ ...prev, [exchange]: false })); - stopHeartbeat(exchange); - - // 自动重连 - if (!reconnectRefs.current[exchange] && subscribedCodes.current[exchange].size > 0) { - reconnectRefs.current[exchange] = setTimeout(() => { - reconnectRefs.current[exchange] = null; - if (subscribedCodes.current[exchange].size > 0) { - createConnection(exchange); + if (exchange === 'SSE') { + const codes = Array.from(subscribedCodes.current.SSE); + if (codes.length > 0) { + ws.send(JSON.stringify({ + action: 'subscribe', + channels: ['stock', 'index'], + codes, + })); } - }, RECONNECT_INTERVAL); - } - }; + } + + startHeartbeat(exchange); + }; + + ws.onmessage = (event: MessageEvent) => { + try { + const msg = JSON.parse(event.data); + handleMessage(exchange, msg); + } catch (e) { + logger.warn('FlexScreen', `${exchange} 消息解析失败`, e); + } + }; + + ws.onerror = (error: Event) => { + logger.error('FlexScreen', `${exchange} WebSocket 错误`, error); + }; + + ws.onclose = () => { + logger.info('FlexScreen', `${exchange} WebSocket 断开`); + setConnected(prev => ({ ...prev, [exchange]: false })); + stopHeartbeat(exchange); + + // 自动重连(仅在非 HTTPS + ws:// 场景下) + if (!reconnectRefs.current[exchange] && subscribedCodes.current[exchange].size > 0) { + reconnectRefs.current[exchange] = setTimeout(() => { + reconnectRefs.current[exchange] = null; + if (subscribedCodes.current[exchange].size > 0) { + createConnection(exchange); + } + }, RECONNECT_INTERVAL); + } + }; + } catch (e) { + logger.error('FlexScreen', `${exchange} WebSocket 连接失败`, e); + setConnected(prev => ({ ...prev, [exchange]: false })); + } }, [startHeartbeat, stopHeartbeat, handleMessage]); const subscribe = useCallback((code: string) => { diff --git a/sse_html.html b/sse_html.html new file mode 100644 index 00000000..8723bda7 --- /dev/null +++ b/sse_html.html @@ -0,0 +1,378 @@ + + + + + + VDE 实时行情 - WebSocket 测试 + + + +
+

VDE 实时行情

+ +
+
+ 未连接 +
+
更新次数: 0
+
最后更新: -
+
+
+ + + +
+
+ +
+ +
+

📊 指数行情

+ + + + + + + + + + + +
代码/名称最新涨跌涨跌幅成交额(亿)
+
+ + +
+

📈 股票行情 (前20)

+ + + + + + + + + + + + +
代码/名称最新涨跌幅买一卖一成交额(万)
+
+
+ + +
+
+ + + + diff --git a/szse_html.html b/szse_html.html new file mode 100644 index 00000000..baf8e8f0 --- /dev/null +++ b/szse_html.html @@ -0,0 +1,289 @@ + + + + + + 深交所行情 WebSocket 测试 + + + +
+

深交所行情 WebSocket 测试

+ +
+ + + + + + 未连接 +
+ +
+
+
0
+
消息总数
+
+
+
0
+
股票 (300111)
+
+
+
0
+
指数 (309011)
+
+
+
0
+
债券 (300211)
+
+
+
0
+
港股 (306311)
+
+
+
0
+
其他类型
+
+
+ +
+
+
+ 实时行情 + -- +
+
+ + + + + + + + + + + +
代码类型最新价涨跌幅成交量
+
+
+
+
+ 消息日志 + 0 条 +
+
+
+
+
+ + + + diff --git a/valuefrontier.conf b/valuefrontier.conf index 9f4e2992..76fac284 100644 --- a/valuefrontier.conf +++ b/valuefrontier.conf @@ -112,6 +112,42 @@ server { proxy_buffering off; } + # ============================================ + # 实时行情 WebSocket 代理(灵活屏功能) + # ============================================ + + # 上交所实时行情 WebSocket + location /ws/sse { + proxy_pass http://49.232.185.254:8765; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $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; + proxy_connect_timeout 7d; + proxy_send_timeout 7d; + proxy_read_timeout 7d; + proxy_buffering off; + } + + # 深交所实时行情 WebSocket + location /ws/szse { + proxy_pass http://222.128.1.157:8765; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $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; + proxy_connect_timeout 7d; + proxy_send_timeout 7d; + proxy_read_timeout 7d; + proxy_buffering off; + } + location /mcp/ { proxy_pass http://127.0.0.1:8900/; proxy_http_version 1.1; @@ -142,7 +178,6 @@ server { } } - # 概念板块API代理 location /concept-api/ { proxy_pass http://222.128.1.157:16801/; @@ -158,6 +193,7 @@ server { proxy_send_timeout 60s; proxy_read_timeout 60s; } + # Elasticsearch API代理(价值论坛) location /es-api/ { proxy_pass http://222.128.1.157:19200/; @@ -223,36 +259,7 @@ server { proxy_send_timeout 86400s; proxy_read_timeout 86400s; } - # AI Chat 应用 (Next.js) - MCP 集成 - # AI Chat 静态资源(图片、CSS、JS) - location ~ ^/ai-chat/(images|_next/static|_next/image|favicon.ico) { - proxy_pass http://127.0.0.1:3000; - proxy_http_version 1.1; - 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; - # 缓存设置 - expires 30d; - add_header Cache-Control "public, immutable"; - } - - # AI Chat 主应用 - location /ai-chat { - proxy_pass http://127.0.0.1:3000; - proxy_http_version 1.1; - 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; - proxy_set_header Cookie $http_cookie; - proxy_pass_request_headers on; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; - proxy_buffering off; - proxy_cache off; - } # iframe 内部资源代理(Bytedesk 聊天窗口的 CSS/JS) location /chat/ { proxy_pass http://43.143.189.195/chat/; @@ -326,6 +333,22 @@ server { add_header Cache-Control "public, max-age=86400"; } + # Bytedesk 文件访问代理(仅 2025 年文件) + location ^~ /file/2025/ { + proxy_pass http://43.143.189.195/file/2025/; + proxy_http_version 1.1; + 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; + + # 缓存配置 + proxy_cache_valid 200 1d; + expires 1d; + add_header Cache-Control "public, max-age=86400"; + add_header Access-Control-Allow-Origin *; + } + # Visitor API 代理(Bytedesk 初始化接口) location /visitor/ {