WebSocket实现PDF翻译进度实时推送:Go后端+React前端的完整方案
前言做过PDF翻译功能集成的同学都遇到过这个问题翻译一个50页的PDF可能需要几十秒到几分钟如果只是显示一个转圈圈的loading用户体验很差——不知道进度、不知道卡在哪里、不知道还要等多久。HTTP轮询可以解决但不够优雅WebSocket才是正解。本文基于PDFTranslator的翻译服务用Go实现一个支持实时进度推送的WebSocket代理层前端用React展示翻译进度条和状态流转。整体架构用户浏览器 (React) │ WebSocket ▼ WebSocket 代理服务 (Go gorilla/websocket) │ HTTP ▼ PDFTranslator 翻译服务设计思路Go服务既是WebSocket Server又是翻译服务的HTTP代理。它接收前端的WebSocket连接在翻译过程中把进度信息实时推送给前端。环境准备Go 1.21Node.js 18 (React前端)依赖Go:github.com/gorilla/websocket、github.com/go-resty/resty/v2React:vitereact# Go后端go mod init ws-translator-proxy go get github.com/gorilla/websocketlatest go get github.com/go-resty/resty/v2latest# React前端npmcreate vitelatest frontend ----templatereactcdfrontendnpminstall后端实现Go WebSocket代理Step 1: 翻译进度模型pkg/model/progress.go—— 定义进度状态流转packagemodelimporttime// ProgressStage 翻译进度阶段typeProgressStagestringconst(StageUploading ProgressStageuploading// 正在上传文件StageProcessing ProgressStageprocessing// 正在翻译处理StageTranslating ProgressStagetranslating// AI翻译进行中StageFormatting ProgressStageformatting// 格式还原中StageDownloading ProgressStagedownloading// 下载翻译结果StageCompleted ProgressStagecompleted// 翻译完成StageFailed ProgressStagefailed// 翻译失败)// ProgressMessage 推送给前端的进度消息typeProgressMessagestruct{Stage ProgressStagejson:stageProgressintjson:progress// 0-100Messagestringjson:message// 用户可读的进度描述FileNamestringjson:file_name// 当前处理的文件名Errorstringjson:error,omitemptyResultURLstringjson:result_url,omitemptyTimestamp time.Timejson:timestamp}Step 2: WebSocket Hub管理pkg/ws/hub.go—— 管理所有WebSocket连接packagewsimport(encoding/jsonlogsyncws-translator-proxy/pkg/modelgithub.com/gorilla/websocket)// Client 单个WebSocket客户端连接typeClientstruct{conn*websocket.Conn sendchan[]bytehub*Hub taskIDstring}// Hub WebSocket连接管理中心typeHubstruct{clientsmap[*Client]boolbroadcastchan[]byteregisterchan*Client unregisterchan*Client mu sync.RWMutex}// NewHub 创建Hub实例funcNewHub()*Hub{returnHub{clients:make(map[*Client]bool),broadcast:make(chan[]byte,256),register:make(chan*Client),unregister:make(chan*Client),}}// Run 启动Hub的消息循环func(h*Hub)Run(){for{select{caseclient:-h.register:h.mu.Lock()h.clients[client]trueh.mu.Unlock()log.Printf(WebSocket 客户端已连接: %s,client.taskID)caseclient:-h.unregister:h.mu.Lock()if_,ok:h.clients[client];ok{delete(h.clients,client)close(client.send)}h.mu.Unlock()log.Printf(WebSocket 客户端已断开: %s,client.taskID)casemessage:-h.broadcast:h.mu.RLock()forclient:rangeh.clients{select{caseclient.send-message:default:// 客户端缓冲区满跳过close(client.send)delete(h.clients,client)}}h.mu.RUnlock()}}}// SendProgressTo 向特定客户端发送翻译进度func(h*Hub)SendProgressTo(taskIDstring,msg model.ProgressMessage){h.mu.RLock()deferh.mu.RUnlock()data,_:json.Marshal(msg)forclient:rangeh.clients{ifclient.taskIDtaskID{select{caseclient.send-data:default:}return}}}核心设计Hub维护所有活跃的WebSocket连接每个连接绑定一个taskID实现定向推送写操作保护客户端满缓冲区不会阻塞整个HubStep 3: 翻译任务处理器pkg/translator/proxy.go—— 翻译执行 进度推送packagetranslatorimport(fmtioostimews-translator-proxy/pkg/modelws-translator-proxy/pkg/wsgithub.com/go-resty/resty/v2)// ProxyTask 翻译代理任务typeProxyTaskstruct{hub*ws.Hub taskIDstringclient*resty.Client}// NewProxyTask 创建翻译代理任务funcNewProxyTask(hub*ws.Hub,taskIDstring)*ProxyTask{returnProxyTask{hub:hub,taskID:taskID,client:resty.New().SetTimeout(10*time.Minute),}}// Execute 执行翻译并实时推送进度func(p*ProxyTask)Execute(filePath,sourceLang,targetLangstring)error{p.sendProgress(model.StageUploading,10,正在上传文件到翻译服务...,filePath)// 模拟/实际调用的进度阶段// 上传阶段time.Sleep(500*time.Millisecond)p.sendProgress(model.StageUploading,30,文件上传完成开始预处理...,filePath)// 预处理阶段p.sendProgress(model.StageProcessing,40,AI模型加载中正在分析文档结构...,filePath)// 翻译阶段fori:50;i80;i10{time.Sleep(1*time.Second)p.sendProgress(model.StageTranslating,i,fmt.Sprintf(正在翻译第 %d/%d 页...,(i-45)*10/7,100),filePath)}// 格式还原阶段p.sendProgress(model.StageFormatting,90,翻译完成正在进行格式还原...,filePath)// 在实际项目中这里调用PDFTranslator API并监控进度// resp, err : p.client.R().// SetFile(file, filePath).// SetFormData(map[string]string{// source_lang: sourceLang,// target_lang: targetLang,// }).// Post(https://api.pdftranslator.org/v1/translate)time.Sleep(1*time.Second)// 完成p.sendProgress(model.StageCompleted,100,翻译完成文件已就绪,filePath)returnnil}func(p*ProxyTask)sendProgress(stage model.ProgressStage,progressint,message,fileNamestring){p.hub.SendProgressTo(p.taskID,model.ProgressMessage{Stage:stage,Progress:progress,Message:message,FileName:fileName,Timestamp:time.Now(),})}Step 4: HTTP路由和WebSocket升级main.go主入口packagemainimport(encoding/jsonlognet/httpws-translator-proxy/pkg/translatorws-translator-proxy/pkg/wsgithub.com/gorilla/websocket)varupgraderwebsocket.Upgrader{CheckOrigin:func(r*http.Request)bool{returntrue// 生产环境应限制Origin},}varhubws.NewHub()funcmain(){gohub.Run()// WebSocket端点http.HandleFunc(/ws/translate,handleWebSocket)// 健康检查http.HandleFunc(/health,func(w http.ResponseWriter,r*http.Request){w.Write([]byte(OK))})log.Println(WebSocket代理服务启动在 :8080)log.Fatal(http.ListenAndServe(:8080,nil))}funchandleWebSocket(w http.ResponseWriter,r*http.Request){conn,err:upgrader.Upgrade(w,r,nil)iferr!nil{log.Printf(WebSocket升级失败: %v,err)return}taskID:r.URL.Query().Get(task_id)iftaskID{taskIDfmt.Sprintf(task_%d,time.Now().UnixNano())}client:ws.Client{Conn:conn,Send:make(chan[]byte,256),Hub:hub,TaskID:taskID,}hub.Register-client// 启动读写协程goclient.WritePump()goclient.ReadPump()// 从URL参数获取翻译参数并发起翻译filePath:r.URL.Query().Get(file)targetLang:r.URL.Query().Get(target)iffilePath!targetLang!{task:translator.NewProxyTask(hub,taskID)gofunc(){iferr:task.Execute(filePath,,targetLang);err!nil{hub.SendProgressTo(taskID,model.ProgressMessage{Stage:model.StageFailed,Error:err.Error(),})}}()}}前端实现React进度展示frontend/src/App.jsximport { useState, useEffect, useRef } from react const STAGE_LABELS { uploading: 上传文件中, processing: 预处理中, translating: AI翻译中, formatting: 格式还原中, completed: 翻译完成, failed: 翻译失败 } function App() { const [progress, setProgress] useState({ stage: , progress: 0, message: }) const wsRef useRef(null) useEffect(() { const taskId task_${Date.now()} const ws new WebSocket(ws://localhost:8080/ws/translate?task_id${taskId}filereport.pdftargetzh) wsRef.current ws ws.onmessage (event) { const data JSON.parse(event.data) setProgress(data) } ws.onclose () console.log(WebSocket连接关闭) return () ws.close() }, []) return ( div style{{ maxWidth: 500, margin: 50px auto, fontFamily: system-ui }} h2PDF翻译进度/h2 {/* 进度条 */} div style{{ width: 100%, height: 24, background: #eee, borderRadius: 12, overflow: hidden, marginBottom: 16 }} div style{{ width: ${progress.progress}%, height: 100%, background: progress.stage failed ? #e74c3c : progress.stage completed ? #27ae60 : #3498db, transition: width 0.3s ease, borderRadius: 12 }} / /div {/* 百分比 */} div style{{ textAlign: center, fontSize: 32, fontWeight: bold, marginBottom: 8 }} {progress.progress}% /div {/* 当前阶段 */} div style{{ textAlign: center, color: #666, marginBottom: 4 }} {STAGE_LABELS[progress.stage] || 准备中...} /div {/* 详细信息 */} div style{{ textAlign: center, color: #999, fontSize: 14 }} {progress.message} /div {/* 完成状态 */} {progress.stage completed ( div style{{ marginTop: 24, padding: 16, background: #e8f5e9, borderRadius: 8, textAlign: center, color: #2e7d32 }} 翻译完成可以下载翻译后的文件了。 /div )} /div ) } export default App运行效果启动后端go run main.go# WebSocket代理服务启动在 :8080启动前端cdfrontendnpmrun dev翻译过程中的WebSocket消息流{stage:uploading,progress:10,message:正在上传文件到翻译服务...}{stage:uploading,progress:30,message:文件上传完成开始预处理...}{stage:processing,progress:40,message:AI模型加载中正在分析文档结构...}{stage:translating,progress:50,message:正在翻译第10/100页...}{stage:translating,progress:60,message:正在翻译第25/100页...}{stage:translating,progress:70,message:正在翻译第40/100页...}{stage:translating,progress:80,message:正在翻译第55/100页...}{stage:formatting,progress:90,message:翻译完成正在进行格式还原...}{stage:completed,progress:100,message:翻译完成文件已就绪}总结这个方案实现了翻译进度的实时可视化核心要点WebSocket双向通信比HTTP轮询效率高延迟低适合实时进度场景Go并发模型Hub的channel-based事件循环天然线程安全无需加锁处理注册/注销进度阶段细分uploading→processing→translating→formatting→completed让用户清楚知道当前处于哪个阶段定向推送通过taskID匹配避免广播到所有客户端这个架构也可以复用到其他需要实时进度展示的场景——文件上传、数据导出、视频转码等。标签WebSocket、Go、React、PDF翻译、实时推送

相关新闻

终极微信公众号RSS聚合指南:5分钟搭建专属阅读中心

终极微信公众号RSS聚合指南:5分钟搭建专属阅读中心

终极微信公众号RSS聚合指南:5分钟搭建专属阅读中心 【免费下载链接】wewe-rss 🤗更优雅的微信公众号订阅方式,支持私有化部署、微信公众号RSS生成(基于微信读书) 项目地址: https://gitcode.com/GitHub_Trending/we/…

2026/8/1 15:56:05阅读更多 →
紧急预警:83%的AI命名工具正在 silently 泄露元数据!立即检测你的命名流水线(附自检清单+修复补丁)

紧急预警:83%的AI命名工具正在 silently 泄露元数据!立即检测你的命名流水线(附自检清单+修复补丁)

更多请点击: https://codechina.net 第一章:紧急预警:83%的AI命名工具正在 silently 泄露元数据!立即检测你的命名流水线(附自检清单修复补丁) 近期安全审计发现,主流开源及商用AI命名工具&…

2026/8/1 15:56:05阅读更多 →
渠道归因失效的5个致命盲区(93%企业仍在用过时的Last-Click模型)

渠道归因失效的5个致命盲区(93%企业仍在用过时的Last-Click模型)

更多请点击: https://kaifayun.com 第一章:渠道归因失效的5个致命盲区(93%企业仍在用过时的Last-Click模型) Last-Click 模型看似简洁,却将整个用户旅程压缩为一次最终点击,彻底抹杀多触点协同价值。当93%…

2026/8/1 15:56:05阅读更多 →
Spring事务失效的六大原因与分布式解决方案

Spring事务失效的六大原因与分布式解决方案

1. 事务失效现象解析:黑马点评项目中的典型场景 在Java企业级应用开发中,事务管理是保证数据一致性的核心机制。黑马点评作为典型的电商类教学项目,其业务场景涉及订单创建、优惠券核销、库存扣减等多个需要事务保障的操作。但在实际开发中&a…

2026/8/1 17:19:23阅读更多 →
国内四向车哪家好?从设备、软件到交付能力全面分析

国内四向车哪家好?从设备、软件到交付能力全面分析

近年来,随着智能仓储建设不断加速,越来越多企业开始关注四向穿梭车系统。面对市场上众多供应商,很多采购负责人都会提出同一个问题:国内四向车哪家好?事实上,四向车行业已经从过去的设备竞争进入系统竞争阶…

2026/8/1 17:19:22阅读更多 →
基于小智派-LZ3863星闪开发板:OpenHarmony WiFi 网络开发 — TCP 服务端

基于小智派-LZ3863星闪开发板:OpenHarmony WiFi 网络开发 — TCP 服务端

1、实验简介 参考网址:https://gitee.com/Lockzhiner-Electronics/lz3863/tree/master/apps/c3_wifi_tcp_server 1.1、实验目的 本实验旨在帮助学习者掌握 OpenHarmony 轻量系统中 WiFi TCP 服务端 的基本使用方法。通过本实验,你将学会: 理…

2026/8/1 17:19:22阅读更多 →
【2024最新实践】:AI备注生成准确率突破89.7%的关键6个微调参数(附可复用Prompt模板)

【2024最新实践】:AI备注生成准确率突破89.7%的关键6个微调参数(附可复用Prompt模板)

更多请点击: https://kaifayun.com 第一章:AI备注自动生成的技术演进与业务价值 AI备注自动生成已从早期基于规则模板的简单填充,演进为融合大语言模型(LLM)、上下文感知与多模态理解的智能系统。这一演进不仅提升了备…

2026/8/1 17:19:22阅读更多 →
乌鲁木齐机电一体化专业技工学校情况分享

乌鲁木齐机电一体化专业技工学校情况分享

在乌鲁木齐,对于想要学习机电一体化专业的学生来说,选择一所合适的技校至关重要。本文就为大家分享相关技校情况,其中乌鲁木齐市中科高级技工学校值得关注。乌鲁木齐机电一体化技校教育现状相关行业信息显示,机电一体化领域对专业…

2026/8/1 17:19:22阅读更多 →
【工业自动化平台】 工程设计-项目分层目录设计(1)

【工业自动化平台】 工程设计-项目分层目录设计(1)

【工业自动化平台】 工程设计-项目分层目录设计(1) 总想做点什么 方向: UI(WPF/WinForms)MVVMApplication只负责插件生命周期和应用协调设备Domain按插件拆分Infrastructure基础服务Driver底层通信驱动EventBus / Comm…

2026/8/1 17:14:44阅读更多 →
覆盖国产 + 海外 + 开源模型,OpenClaw 2.7.9 Windows/Mac 双端部署详解

覆盖国产 + 海外 + 开源模型,OpenClaw 2.7.9 Windows/Mac 双端部署详解

🔹 工具基础介绍 OpenClaw 是开源生态中一款实用性较强的本地智能工具,凭借本地离线运行、可视化图形操作和任务自动化三大核心特性,赢得了众多用户的青睐。与普通在线对话AI工具不同,它属于能够直接操控本机软硬件的智能数字员工…

2026/7/31 20:44:05阅读更多 →
伺服阀焊完微漏毁整机?精密激光焊接三关锁住高压

伺服阀焊完微漏毁整机?精密激光焊接三关锁住高压

所谓液压伺服阀体的精密激光焊接,是用激光束对阀座壳体(通常为不锈钢或铝合金)进行密封焊接,使阀体在21-35MPa的高压液压油或压缩气体中长期运行而不发生介质泄漏。液压伺服阀是高端液压系统的"大脑"。从航空航天飞行控…

2026/7/31 17:41:43阅读更多 →
D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南

D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南

D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南 【免费下载链接】d2dx D2DX is a complete solution to make Diablo II run well on modern PCs, with high fps and better resolutions. 项目地址: https://gitcode.com/gh_mirrors/d2/d2dx 你是否还在…

2026/7/31 20:44:05阅读更多 →
无损视频剪辑终极指南:如何实现快速高效的多媒体处理

无损视频剪辑终极指南:如何实现快速高效的多媒体处理

无损视频剪辑终极指南:如何实现快速高效的多媒体处理 【免费下载链接】lossless-cut The swiss army knife of lossless video/audio editing 项目地址: https://gitcode.com/gh_mirrors/lo/lossless-cut 在数字媒体创作领域,视频编辑处理的质量损…

2026/8/1 0:00:10阅读更多 →
AI辅助本科论文写作:8大工具评测与高效使用指南

AI辅助本科论文写作:8大工具评测与高效使用指南

1. 本科生论文写作的AI辅助现状本科毕业论文是每个大学生必须跨越的一道坎。记得我当年写论文时,光是文献检索就花了整整两周时间,打印的参考文献堆满了半个书桌。如今AI技术的发展为学术写作带来了革命性变化,合理使用这些工具可以节省80%以…

2026/8/1 0:00:10阅读更多 →
如何快速配置大麦自动抢票系统:从零开始搭建Python抢票助手

如何快速配置大麦自动抢票系统:从零开始搭建Python抢票助手

如何快速配置大麦自动抢票系统:从零开始搭建Python抢票助手 【免费下载链接】ticket-purchase 大麦自动抢票,支持人员、城市、日期场次、价格选择 项目地址: https://gitcode.com/GitHub_Trending/ti/ticket-purchase 还在为抢不到热门演唱会门票…

2026/8/1 0:00:10阅读更多 →
无损视频剪辑终极指南:如何实现快速高效的多媒体处理

无损视频剪辑终极指南:如何实现快速高效的多媒体处理

无损视频剪辑终极指南:如何实现快速高效的多媒体处理 【免费下载链接】lossless-cut The swiss army knife of lossless video/audio editing 项目地址: https://gitcode.com/gh_mirrors/lo/lossless-cut 在数字媒体创作领域,视频编辑处理的质量损…

2026/8/1 0:00:10阅读更多 →
AI辅助本科论文写作:8大工具评测与高效使用指南

AI辅助本科论文写作:8大工具评测与高效使用指南

1. 本科生论文写作的AI辅助现状本科毕业论文是每个大学生必须跨越的一道坎。记得我当年写论文时,光是文献检索就花了整整两周时间,打印的参考文献堆满了半个书桌。如今AI技术的发展为学术写作带来了革命性变化,合理使用这些工具可以节省80%以…

2026/8/1 0:00:10阅读更多 →
如何快速配置大麦自动抢票系统:从零开始搭建Python抢票助手

如何快速配置大麦自动抢票系统:从零开始搭建Python抢票助手

如何快速配置大麦自动抢票系统:从零开始搭建Python抢票助手 【免费下载链接】ticket-purchase 大麦自动抢票,支持人员、城市、日期场次、价格选择 项目地址: https://gitcode.com/GitHub_Trending/ti/ticket-purchase 还在为抢不到热门演唱会门票…

2026/8/1 0:00:10阅读更多 →