编程自学网编程自学网编程自学网

将文本流从NodeJS传递到浏览器

问题描述:

我正在尝试将NodeJS中处理的文本文件流式传输到浏览器。以下是处理之前的文本文件。该文件名为dbUsers.json。

{"userId":443,"email":"bob@gmail.com","hashedPassword":"36583a77a098c02ef111e2f2521d77b58e420f2bc7e9bf930ec24b21d42ea2e0","timeStamp":1567439821109,"deleted":false}
{"userId":447,"email":"alice@gmail.com","hashedPassword":"36583a77a098c02ef111e2f2521d77b58e420f2bc7e9bf930ec24b21d42ea2e0","timeStamp":1567439909013,"deleted":false}
{"userId":451,"email":"cliff@gmail.com","hashedPassword":"36583a77a098c02ef111e2f2521d77b58e420f2bc7e9bf930ec24b21d42ea2e0","timeStamp":1567443638340,"deleted":false}
...

处理后,我可以使用以下命令将数据流式传输到NodeJS服务器上的新文件:

// Create a writable stream and specify the file which will receive the data from the readable stream.let destinationStream = fs.createWriteStream(_data.baseDir + '/dbPermissions/dbUsers' + '/' + 'test' + '.txt', {flags : 'a'});


pipeline
(
  sourceStream,
  destinationStream,  function(error){if(error){console.log('There was an error.');}}
);

新文件显示按预期处理的数据。一些字段已被删除,标记为删除的记录也已删除。这表明sourceStream在起作用。现在,新文件中的数据如下:

{"userId":443,"email":"bob@gmail.com","timeStamp":1567439821109}
{"userId":447,"email":"alice@gmail.com","timeStamp":1567439909013}
{"userId":451,"email":"cliff@gmail.com","timeStamp":1567443638340}
...

在将SourceStream流传输到客户端浏览器之前,将它记录到NodeJS控制台会产生以下输出。

Readable {
  _readableState:
   ReadableState {
     objectMode: false,
     highWaterMark: 16384,
     buffer: BufferList { head: [Object], tail: [Object], length: 45 },
     length: 3035,
     pipes:
      WriteStream {
        _writableState: [WritableState],
        writable: true,
        domain: null,
        _events: [Object],
        _eventsCount: 6,
        _maxListeners: undefined,
        path:
         'C:\\Users\\user\\Desktop\\Tutorials\\iotajs\\ias\\accounting\\/dbPermissions/dbUsers/test.txt',
        fd: null,
        flags: 'a',
        mode: 438,
        start: undefined,
        autoClose: true,
        pos: undefined,
        bytesWritten: 0,
        closed: false },
     pipesCount: 1,
     flowing: true,
     ended: true,
     endEmitted: false,
     reading: false,
     sync: true,
     needReadable: false,
     emittedReadable: true,
     readableListening: false,
     resumeScheduled: true,
     paused: false,
     emitClose: true,
     destroyed: false,
     defaultEncoding: 'utf8',
     awaitDrain: 0,
     readingMore: true,
     decoder: null,
     encoding: null },
  readable: true,
  domain: null,
  _events:
   [Object: null prototype] {
     close: [ [Function], [Function: onclose] ],
     end: [ [Function: onend], [Function] ],
     finish: [Function: onfinish],
     error: [Function: onerror],
     data: [Function: ondata] },
  _eventsCount: 5,
  _maxListeners: undefined }Returning this response:  200Returning this response:  200

[将sourceStream流传输到浏览器,然后将responseTextStream记录到浏览器的控制台时,输出与上面相同。因此,我确信sourceStream会使用新名称responseTextStream完整地到达客户端。

我需要使用的数据可能已锁定在上面对象的buffer属性,现在在上面称为responseTextStream客户端浏览器。

我的问题是我不知道如何访问缓冲区,我也不知道如何将其从数字转换回文本。

以下是我希望的客户端浏览器中的功能使用缓冲区中的数据。这是我需要帮助的地方-我不知道如何访问信息流。谢谢,约翰

// Populate the dbUsersList webpage with user records.app.loadUsersListPage = function(){  
  // Ask the server for the JSON records found in the dbUsers file.
  // Then run the callback function defined here which inserts rows into the usersListTable on the webpage
  // and populates them with data from the file of JSON records returned.
  app.client.request(undefined,'api/aUsers','GET',QueryStringObject,undefined,function(statusCode,responseTextStream)  {    // if the call to handlers._users.get which is mapped to api/aUsers called back success.
    if(statusCode == 200) 
    {      // The streamed data can be seen on the console as a buffer full of numbers
      console.log(responseTextStream._readableState.buffer.head.data.data);      // Create a handle which can be used to manipulate the table on the webpage.
      var table = document.getElementById("usersListTable");      // The pseudocode below does not work but is shows what I hope to accomplish. 
      // The line below does not help to access the stream. This is where I need help.
      // What line or lines of code would facilitate access to the stream and allow 
      // processing it as a string, character by character, as shown below.
      var Astr = responseTextStream;      var line = "";      for(var i=0; i<Astr.length; i++)
      {        var chr = String.fromCharCode(Astr[i]);        if(chr == "\n" || chr == "\r")
        {          // Look at each line of json at the console as it is consumed.
          console.log("line: ",line);          // Turn the line, which is a json string, back into a json object 
          var recordObject = JSON.parse(line);          if(recordObject)
          {            // Insert a new row in the table.
            var tr = table.insertRow(-1);            // Make the new row a member of the class 'checkRow'
            tr.classList.add('checkRow');            // Insert five new cells into the new row.
            var td0 = tr.insertCell(0);            var td1 = tr.insertCell(1);            var td2 = tr.insertCell(2);   
            var td3 = tr.insertCell(3);          

            // load the new cells with data from the recordObject.
            td0.innerHTML = recordObject.userId;      
            td1.innerHTML = recordObject.email;
            td2.innerHTML = recordObject.timeStamp;      
            td3.innerHTML = '<a href="/users/edit?email=' + recordObject.userId + '">View / Edit / Delete</a>';
          } // End of: if(recordObject)

          // clear the line buffer to start the next line.
          line = "";

        } // End of: if(chr == "\n" || chr == "\r"){do stuff}
        else 
        {
            line += chr;
        }           

      }; // End of: for(var i=0; i<Astr.length; i++){...}

    } // End of: if the call to handlers._users.get which is mapped to api/aUsers called back successfully.

  }); // End of: app.client.request(undefined,'api/checks','GET'...} // End of: app.loadUsersListPage = function(){...}// End of: Populate the dbUsersList webpage with user records.


解决方法:

由于您使用的是Chrome,因此您可以在一个漂亮的管道中使用所有新功能,例如TextDecoderStream和TransformStream,该管道可以从HTTP响应中流式传输数据,并以行分隔的JSON进行解码。检查一下:

const fetchPromise = fetch(url, params).then((res) => {  // Verify that we have some sort of 2xx response that we can use
  if (!res.ok) {    throw res;
  }  // If no content, immediately resolve, don't try to parse JSON
  if (res.status === 204) {    return;
  }  let textBuffer = '';  const self = this;  return res.body    // Decode as UTF-8 Text
    .pipeThrough(new TextDecoderStream())    // Split on lines
    .pipeThrough(new TransformStream({
      transform(chunk, controller) {
        textBuffer += chunk;        const lines = textBuffer.split('\n');        for (const line of lines.slice(0, -1)) {
          controller.enqueue(line);
        }
        textBuffer = lines.slice(-1)[0];
      },
      flush(controller) {        if (textBuffer) {
          controller.enqueue(textBuffer);
        }
      }
    }))    // Parse JSON objects
    .pipeThrough(new TransformStream({
      transform(line, controller) {        if (line) {
          controller.enqueue(            JSON.parse(line)
          );
        }
      }
    }));
});

现在,您可以像其他任何对象一样使用此新对象流:

  const res = await fetchPromise;  const reader = res.getReader();  function read() {
    reader.read().then(({value, done}) => {      if (value) {        // Your object will be here
      }      if (done) {        return;
      }
      read();
    });
  }
  read();

((注意:我尚未在此示例上下文中测试此代码...我从一个项目中对其进行了修改,因此请仔细研究并使其适合您的特定目的。)


未经允许不得转载:编程自学网 » 将文本流从NodeJS传递到浏览器