首页 > 解决方案 > 节点中的事件流:在控制台中工作正常但不写入流

问题描述

我想将事件流式传输到 localhost/czml - 这在控制台或获取请求窗口中工作正常。但我无法将这些变量流式传输到页面,因为 req.query 总是最终未定义

我是编程的血腥初学者,大多数时候我不知道自己在做什么(这就是代码如此糟糕的原因......)。我通过反复试验获得了该代码,主要是通过从某个地方复制

var express = require('express'),
    fs = require('fs'),
    morgan = require('morgan'),
    path = require('path'),
    os = require('os'),
    http = require('http');

    const app = express();
    const EventEmitter = require('events');
    const stream = new EventEmitter();
    var czmlstream = fs.createWriteStream('czml.czml',{flags: 'a'});


    app.get('/czml', function (req, res, next) {
    //don't log favicon
    if (req.url === '/favicon.ico'){
        res.end();
        return;
    }

    //only log GET and set to stream
    if (req.method === 'GET' ) {
    res.writeHead(200, {
        'Content-Type': 'text/event-stream',
        'Cache-Control': 'no-cache',
        'Connection': 'keep-alive'
    });

    function createCzml() {
        //get the query value from the request
        var id = req.query.id;
        var lon = parseInt(req.query.lon);
        var lat = parseInt(req.query.lat);
        var alt = parseInt(req.query.alt);

        // custom json format for czml file
        var entity = {
            "id": id,
            "position": {
                "cartographicDegrees": [lat, lon, alt]
            },
            "point": {
                "color" : {"rgba": [0,0,255,255]},
            "pixelSize": 20
            }
        };
        return entity;

    }   
        //first 2 lines for the event stream
    res.write('event: czml\n');
    res.write('data:' + JSON.stringify({ "id":"document", "version":"1.0" })+   
    '\n\n');

    //always tells me that 10 listeners are added .... ?
    stream.setMaxListeners(0);

    //stream.on(req) = emit event on get request?
    stream.on('req', function() {
        res.write('event: czml\n');
        res.write('data:' +JSON.stringify(createCzml)+ '\n\n'); //this 
    doesn't work
    });
    //not sure why this is needed
    stream.emit('req');
    }else{
        res.WriteHead(405, {'Content-Type': 'text/plain'});
        res.end('No GET Request - not allowed');
    }

    //morgan(format, {stream: czmlstream})(req,res,next);   
    }).listen(8000);
    console.log('Server running');

我想要实现的目标:有人向 localhost/czml/?id=1&lon=-40&lat=30&alt=5000 => 发送一个 get 请求 => 这些查询被解析并以以下格式作为事件流发送到 localhost/whatever:

事件:czml 数据:{json}

我快到了(即使代码很糟糕)——这只是我必须将那些讨厌的查询写到 localhost/whatever 的最后一部分。现在它在控制台中记录一切正常,但未定义被写入 localhost/whatever...

如果您能指出正确的方向,我将不胜感激 - 但请记住,我需要简单而好的解释;)

标签: javascriptnode.jsevent-handlingczml

解决方案


好的,我自己解决了这个问题,仅供其他一些新手参考:

基本上就是这个示例,只有侦听器(据我所知)用于获取请求

    // most basic dependencies
var express = require('express')
  , http = require('http')
  , os = require('os')
  , path = require('path')
  , url = require('url')
  , fs = require('fs');

// create the app
var app = express();

// configure everything, just basic setup
//app.set('port', process.env.PORT || 8000);
app.use(function(req, resp, next) {
  resp.header("Access-Control-Allow-Origin", "*");
  resp.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
  next();
});

// Serve the www directory statically
app.use(express.static('www'));

//---------------------------------------
// Handle Get request and event-stream every second
//---------------------------------------
var openConnections = [];

var id, lon, lat, alt;

app.get('/czml', function(req, res, next) {
    //don't log favicon
    if (req.url === '/favicon.ico'){
        res.end();
        return;
    } else {

    var queryData = url.parse(req.url, true).query;
    id = queryData.id;
    lon = queryData.lon;
    lat = queryData.lat;
    alt = queryData.alt;

    req.socket.setTimeout(2 * 60 * 1000);

    // send headers for event-stream connection
    // see spec for more information
    res.writeHead(200, {
        'Content-Type': 'text/event-stream',
        'Cache-Control': 'no-cache',
        'Connection': 'keep-alive'
    });
    res.write('\n');

    // push this res object to our global variable
    openConnections.push(res);

    // send document packet
    res.write('event: czml\ndata:' + JSON.stringify({ "id":"document", "version":"1.0" })+   '\n\n');

    // When the request is closed, e.g. the browser window
    // is closed. We search through the open connections
    // array and remove this connection.
    req.on("close", function() {
        var toRemove;
        for (var j =0 ; j < openConnections.length ; j++) {
            if (openConnections[j] == res) {
                toRemove =j;
                break;
            }
        }
        openConnections.splice(j,1);
    });
    next();
    }
}).listen(8000);

function createMsg() {
        var entity = {
            "id" : id,
            "position" : {
                "cartographicDegrees": [lon,lat,alt]
            },
            "point" : { 
                "color" : {
                    "rgba" : [0,0,255,255]
                },
                "pixelSize" : 15
            }

        };
        return JSON.stringify(entity);;
    }

setInterval(function() {
    // we walk through each connection
    openConnections.forEach(function(res) {
        // send doc
        res.write('event: czml\n');
        res.write('data:' + createMsg() +   '\n\n');
    });
}, 1000);

我不知道这在 SO 上是如何工作的 - 以上并不是我问题的真正答案 - 更多的是一种解决方法。但它有效,所以我想这很好:)


推荐阅读