# EPEEKit 内网穿透启动脚本 # 使用 Cloudflare Quick Tunnel(无需账号,免费) # 用法:在 PowerShell 中执行 .\start-tunnel.ps1 param( [int]$BackendPort = 8000, [int]$FrontendPort = 3000 ) $ErrorActionPreference = "Stop" # 优先使用与本脚本同目录的 cloudflared.exe(避免未安装 / 未加入 PATH) $LocalCf = Join-Path $PSScriptRoot "cloudflared.exe" if (Test-Path -LiteralPath $LocalCf) { $env:Path = "$PSScriptRoot;$env:Path" } # 检查 cloudflared 是否可用 try { $null = Get-Command cloudflared -ErrorAction Stop } catch { Write-Host "[错误] 未找到 cloudflared,请先安装:winget install Cloudflare.cloudflared" -ForegroundColor Red exit 1 } Write-Host "" Write-Host " ╔═══════════════════════════════════════════╗" -ForegroundColor Cyan Write-Host " ║ EPEEKit 内网穿透 ║" -ForegroundColor Cyan Write-Host " ╚═══════════════════════════════════════════╝" -ForegroundColor Cyan Write-Host "" # 启动后端穿透 Write-Host "[1/2] 启动后端穿透隧道 (localhost:$BackendPort)..." -ForegroundColor Yellow $backendTunnel = Start-Process cloudflared -ArgumentList "tunnel", "--url", "http://localhost:$BackendPort" ` -PassThru -RedirectStandardError "$env:TEMP\epeekit-tunnel-backend.log" -WindowStyle Hidden Start-Sleep -Seconds 3 # 从日志中提取后端公网 URL $backendUrl = "" for ($i = 0; $i -lt 10; $i++) { if (Test-Path "$env:TEMP\epeekit-tunnel-backend.log") { $logContent = Get-Content "$env:TEMP\epeekit-tunnel-backend.log" -Raw -ErrorAction SilentlyContinue if ($logContent -match '(https://[a-z0-9-]+\.trycloudflare\.com)') { $backendUrl = $Matches[1] break } } Start-Sleep -Seconds 2 } if (-not $backendUrl) { Write-Host "[错误] 无法获取后端穿透地址,请检查 cloudflared 日志" -ForegroundColor Red Write-Host " 日志路径: $env:TEMP\epeekit-tunnel-backend.log" Stop-Process -Id $backendTunnel.Id -Force -ErrorAction SilentlyContinue exit 1 } Write-Host " 后端穿透地址: $backendUrl" -ForegroundColor Green # 更新前端环境变量(避免 PS5.1 对 UTF-8 here-string 解析问题,改用 WriteAllLines) $envFile = Join-Path $PSScriptRoot "frontend\.env.local" $envLines = @( "# Backend API URL (updated by start-tunnel.ps1)" "NEXT_PUBLIC_API_URL=$backendUrl" ) [System.IO.File]::WriteAllLines($envFile, $envLines, [System.Text.UTF8Encoding]::new($false)) Write-Host " Updated frontend\.env.local" -ForegroundColor Green Write-Host "" # 启动前端穿透 Write-Host "[2/2] 启动前端穿透隧道 (localhost:$FrontendPort)..." -ForegroundColor Yellow $frontendTunnel = Start-Process cloudflared -ArgumentList "tunnel", "--url", "http://localhost:$FrontendPort" ` -PassThru -RedirectStandardError "$env:TEMP\epeekit-tunnel-frontend.log" -WindowStyle Hidden Start-Sleep -Seconds 3 $frontendUrl = "" for ($i = 0; $i -lt 10; $i++) { if (Test-Path "$env:TEMP\epeekit-tunnel-frontend.log") { $logContent = Get-Content "$env:TEMP\epeekit-tunnel-frontend.log" -Raw -ErrorAction SilentlyContinue if ($logContent -match '(https://[a-z0-9-]+\.trycloudflare\.com)') { $frontendUrl = $Matches[1] break } } Start-Sleep -Seconds 2 } if (-not $frontendUrl) { Write-Host "[错误] 无法获取前端穿透地址" -ForegroundColor Red Stop-Process -Id $backendTunnel.Id -Force -ErrorAction SilentlyContinue Stop-Process -Id $frontendTunnel.Id -Force -ErrorAction SilentlyContinue exit 1 } Write-Host " 前端穿透地址: $frontendUrl" -ForegroundColor Green Write-Host "" Write-Host " ╔═══════════════════════════════════════════╗" -ForegroundColor Green Write-Host " ║ 穿透隧道已就绪! ║" -ForegroundColor Green Write-Host " ╚═══════════════════════════════════════════╝" -ForegroundColor Green Write-Host "" Write-Host " 手机浏览器访问: $frontendUrl" -ForegroundColor Cyan Write-Host " 后端 API: $backendUrl" -ForegroundColor Cyan Write-Host "" Write-Host " [重要] 前端需要重启才能读取新的 .env.local" -ForegroundColor Yellow Write-Host " [提示] 按 Ctrl+C 或关闭此窗口停止穿透" -ForegroundColor DarkGray Write-Host "" # 等待用户中断 try { Write-Host "隧道运行中... (按 Ctrl+C 停止)" -ForegroundColor DarkGray while ($true) { Start-Sleep -Seconds 5 # 检查进程是否还活着 if ($backendTunnel.HasExited) { Write-Host "[警告] 后端隧道已断开" -ForegroundColor Red break } if ($frontendTunnel.HasExited) { Write-Host "[警告] 前端隧道已断开" -ForegroundColor Red break } } } finally { Write-Host "" Write-Host "正在关闭隧道..." -ForegroundColor Yellow Stop-Process -Id $backendTunnel.Id -Force -ErrorAction SilentlyContinue Stop-Process -Id $frontendTunnel.Id -Force -ErrorAction SilentlyContinue # 恢复 .env.local 为 localhost $restoreLines = @( "# Backend API URL" "NEXT_PUBLIC_API_URL=http://localhost:8000" ) [System.IO.File]::WriteAllLines($envFile, $restoreLines, [System.Text.UTF8Encoding]::new($false)) Write-Host "Restored .env.local to localhost" -ForegroundColor Green Write-Host "隧道已关闭" -ForegroundColor Green }