如何基于Server Sent Event实现网页实时展示Bash脚本运行输出
问题原因及修复方案
核心问题1:后端SSE消息格式不符合协议要求
SSE 规范要求每条消息必须以data: 开头,且消息结束需要两个连续的换行符,你当前的输出格式不符合要求,浏览器无法识别为合法的message事件,自然不会触发前端的监听回调。
核心问题2:缓冲区刷新顺序错误
PHP中需要先执行ob_flush()清空PHP自身的输出缓冲区,再执行flush()将内容推送到web服务器,顺序搞反会导致内容无法实时输出。
核心问题3:前端多余JSON解析逻辑报错
你的后端返回的是ping命令的纯文本输出,不是JSON格式,前端代码中data=JSON.parse(e.data);这一行会直接抛出JS异常,后续的DOM更新逻辑不会执行,打开浏览器控制台就能看到对应的报错。
核心问题4:可能存在跨域问题
如果你是直接本地打开HTML文件(地址栏是file://开头),而非通过http://localhost访问的话,会触发跨域限制,SSE请求会被拦截。
修改后的代码
后端 prova_ping.php 代码
<?php header('Content-Type: text/event-stream'); header('Cache-Control: no-cache'); header('Content-Encoding: none'); // 禁用gzip压缩避免攒包 // 如果存在跨域需求可以加下面这行 // header('Access-Control-Allow-Origin: *'); // 清空之前可能存在的输出缓冲 while (ob_get_level()) { ob_end_clean(); } $proc = popen("ping -c4 www.google.com", 'r'); while (!feof($proc)) { // 逐行读取输出,避免一次读多行导致格式问题 $line = fgets($proc); if ($line !== false) { // 严格按照SSE格式输出 echo "data: " . htmlspecialchars($line) . "\n\n"; ob_flush(); flush(); } } pclose($proc); ?>
前端HTML代码
<html> <head> <meta http-equiv="Content-Type" content="text/html;charset=utf-8"> </head> <body> <div id="result">put data out here</div> <script type="text/javascript"> function eventsourcetest(){ var source = new EventSource("http://localhost/prova_ping.php"); source.addEventListener("message", function(e) { if (e.data.trim() !== "") { // 删掉了错误的JSON.parse逻辑 document.getElementById("result").innerHTML += e.data + "<br>"; } }, false); source.addEventListener("error", function(e) { alert("errore!"); source.close(); }, false); } </script> <p><button type="button" onclick="eventsourcetest();">ping google.com</button> </body> </html>
额外注意事项
- 确保你的HTML页面是通过
http://localhost域名访问,不要直接打开本地文件 - 如果Apache开启了mod_deflate压缩,可以临时对prova_ping.php路径禁用压缩,避免内容被攒到一定大小才返回
- 如果要执行其他bash脚本,注意做好命令参数的过滤,避免命令注入漏洞
内容的提问来源于stack exchange,提问作者emilio de franco
相关产品推荐
相关产品推荐

