nodejs / express – streamstdout立即到客户端

我产生了下面的孩子: var spw = spawn('ping', ['-n','10', '127.0.0.1'])我想在客户端( 浏览器一个 ,而不是一个整体。

到目前为止,我试过这个:

 app.get('/path', function(req, res) { ... spw.stdout.on('data', function (data) { var str = data.toString(); res.write(str + "\n"); }); ... } 

然后:

 ... spw.stdout.pipe(res); ... 

在这两种情况下,浏览器等待10个ping完成,然后打印整个结果。 我想一个接一个,怎么做到的?

(客户端正在调用.../path和console.logs结果)


编辑:虽然我确实认为,websockets是必要的,我只是想知道是否有任何其他的方式。 我看到了几个令人困惑的SO答案 ,博客post(在这篇文章中,在第一步OP把日志发送到浏览器),这没有帮助,所以我决定去寻求一些关注。

       

网上收集的解决方案 "nodejs / express – streamstdout立即到客户端"

这是一个使用SSE(服务器发送事件)的完整示例。 这在Firefox和Chrome可能也适用:

 var cp = require("child_process"), express = require("express"), app = express(); app.configure(function(){ app.use(express.static(__dirname)); }); app.get('/msg', function(req, res){ res.writeHead(200, { "Content-Type": "text/event-stream", "Cache-control": "no-cache" }); var spw = cp.spawn('ping', ['-c', '100', '127.0.0.1']), str = ""; spw.stdout.on('data', function (data) { str += data.toString(); // just so we can see the server is doing something console.log("data"); // Flush out line by line. var lines = str.split("\n"); for(var i in lines) { if(i == lines.length - 1) { str = lines[i]; } else{ // Note: The double-newline is *required* res.write('data: ' + lines[i] + "\n\n"); } } }); spw.on('close', function (code) { res.end(str); }); spw.stderr.on('data', function (data) { res.end('stderr: ' + data); }); }); app.listen(4000); 

和客户端的HTML:

 <!DOCTYPE Html> <html> <body> <ul id="eventlist"> </ul> <script> var eventList = document.getElementById("eventlist"); var evtSource = new EventSource("http://localhost:4000/msg"); var newElement = document.createElement("li"); newElement.innerHTML = "Messages:"; eventList.appendChild(newElement); evtSource.onmessage = function(e) { console.log("received event"); console.log(e); var newElement = document.createElement("li"); newElement.innerHTML = "message: " + e.data; eventList.appendChild(newElement); }; evtSource.onerror = function(e) { console.log("EventSource failed."); }; console.log(evtSource); </script> </body> </html> 

运行node index.js并将浏览器指向http://localhost:4000/client.html 。 请注意,自从我运行OS X以来,我不得不使用“-c”选项而不是“-n”。

如果您使用的是Google Chrome浏览器,则将内容types更改为“文本/事件stream”即可满足您的需求。

 res.writeHead(200, { "Content-Type": "text/event-stream" }); 

完整示例请参阅我的要点: https : //gist.github.com/sfarthin/9139500

这是标准的HTTP请求/响应周期无法实现的。 基本上你要做的是做一个“推”或“实时”的服务器。 这只能通过xhr-polling或者websockets来实现。

代码示例1:

 app.get('/path', function(req, res) { ... spw.stdout.on('data', function (data) { var str = data.toString(); res.write(str + "\n"); }); ... } 

此代码从不发送结束信号,因此将永远不会回应。 如果您要在该事件处理程序中添加对res.end()的调用,则只会获得第一个ping – 这是预期的行为,因为您将在标准输出的第一个数据块之后结束响应stream。

代码示例2:

 spw.stdout.pipe(res); 

这里stdout将数据包刷新到浏览器,但浏览器将不会呈现数据块,直到收到所有数据包。 这就是为什么它等待10秒,然后渲染整个标准输出。 这种方法的主要好处是不会在发送之前缓冲内存中的响应 – 保持轻量级的内存占用。