开播页:预览放大;信令重连上限与健康检查提示 502

Made-with: Cursor
This commit is contained in:
whm
2026-03-26 11:46:22 +08:00
parent 8c9c573a1c
commit 26e90c30f9
2 changed files with 40 additions and 12 deletions

View File

@@ -57,6 +57,14 @@ function liveWsURLPublish(token) {
const defaultIce = [{ urls: 'stun:stun.l.google.com:19302' }] const defaultIce = [{ urls: 'stun:stun.l.google.com:19302' }]
const MAX_SIGNAL_RECONNECT = 15
function healthCheckUrl() {
if (apiBase) return `${apiBase}/api/health`
if (typeof window !== 'undefined') return `${window.location.origin}/api/health`
return '/api/health'
}
function buildCameraConstraints(publishKey, videoDeviceId) { function buildCameraConstraints(publishKey, videoDeviceId) {
const preset = QUALITY_MEDIA[publishKey] || QUALITY_MEDIA.source const preset = QUALITY_MEDIA[publishKey] || QUALITY_MEDIA.source
const dev = videoDeviceId ? { deviceId: { exact: videoDeviceId } } : {} const dev = videoDeviceId ? { deviceId: { exact: videoDeviceId } } : {}
@@ -130,6 +138,7 @@ export function startPublishing(opts = {}) {
let reconnectTimer = null let reconnectTimer = null
let reconnectAttempt = 0 let reconnectAttempt = 0
let wsGen = 0 let wsGen = 0
let reconnectStopped = false
function clearReconnectTimer() { function clearReconnectTimer() {
if (reconnectTimer) { if (reconnectTimer) {
@@ -254,20 +263,36 @@ export function startPublishing(opts = {}) {
} }
function scheduleReconnect() { function scheduleReconnect() {
if (closedByLocal) return if (closedByLocal || reconnectStopped) return
clearReconnectTimer() clearReconnectTimer()
const delay = Math.min(2000 * Math.pow(1.45, reconnectAttempt), 28000)
reconnectAttempt += 1 reconnectAttempt += 1
onStatus(`信令断开,${Math.round(delay / 1000)} 秒后重连(${reconnectAttempt})…`) if (reconnectAttempt > MAX_SIGNAL_RECONNECT) {
reconnectTimer = window.setTimeout(() => { reconnectStopped = true
onStatus(
`信令已重试 ${MAX_SIGNAL_RECONNECT} 次仍失败。多为 API 返回 502进程未启动/崩溃)或 Nginx 未正确反代到 Go。请检查服务与 \`/api/web/live/ws\` 的 WebSocket 配置,修复后刷新本页再点「开始直播」。`
)
return
}
const delay = Math.min(2000 * Math.pow(1.45, reconnectAttempt - 1), 28000)
onStatus(`信令断开,约 ${Math.round(delay / 1000)} 秒后重试(${reconnectAttempt}/${MAX_SIGNAL_RECONNECT})…`)
reconnectTimer = window.setTimeout(async () => {
reconnectTimer = null reconnectTimer = null
if (closedByLocal) return if (closedByLocal || reconnectStopped) return
try {
const r = await fetch(healthCheckUrl(), { method: 'GET', cache: 'no-store' })
if (!r.ok) {
onStatus(`API 不可用HTTP ${r.status}),多为网关 502推迟重试…`)
}
} catch (_) {
onStatus('无法访问健康检查接口,请确认网络与域名。')
}
if (closedByLocal || reconnectStopped) return
openSignalingSocket() openSignalingSocket()
}, delay) }, delay)
} }
function openSignalingSocket() { function openSignalingSocket() {
if (closedByLocal) return if (closedByLocal || reconnectStopped) return
const myGen = ++wsGen const myGen = ++wsGen
clearReconnectTimer() clearReconnectTimer()
if (ws) { if (ws) {
@@ -321,6 +346,7 @@ export function startPublishing(opts = {}) {
function stop() { function stop() {
closedByLocal = true closedByLocal = true
reconnectStopped = true
wsGen += 1 wsGen += 1
clearReconnectTimer() clearReconnectTimer()
if (ws) { if (ws) {

View File

@@ -133,7 +133,7 @@ onBeforeRouteLeave(() => {
<style scoped> <style scoped>
.live-broadcast { .live-broadcast {
max-width: 720px; max-width: min(1200px, 100%);
} }
.status { .status {
color: #409eff; color: #409eff;
@@ -160,21 +160,23 @@ onBeforeRouteLeave(() => {
} }
.preview-wrap { .preview-wrap {
position: relative; position: relative;
max-width: 720px; width: 100%;
max-width: 1100px;
} }
.preview-main { .preview-main {
display: block; display: block;
width: 100%; width: 100%;
max-height: 70vh; min-height: 320px;
max-height: min(85vh, 900px);
border-radius: 8px; border-radius: 8px;
background: #000; background: #000;
object-fit: contain; object-fit: contain;
} }
.preview-pip { .preview-pip {
position: absolute; position: absolute;
right: 12px; right: 14px;
bottom: 12px; bottom: 14px;
width: min(28%, 200px); width: min(32%, 280px);
aspect-ratio: 4 / 3; aspect-ratio: 4 / 3;
border-radius: 8px; border-radius: 8px;
border: 2px solid #409eff; border: 2px solid #409eff;