首页 > 解决方案 > 如何最好地从 nodejs 网络响应中提取内容主体?

问题描述

使用以下代码:

var net = require("net");
var client = new net.Socket();
client.connect(8080,"localhost",function() {
    client.write("GET /edsa-jox/testjson.json HTTP/1.1\r\n");
    client.write("Accept-Encoding: gzip\r\n");
    client.write("Host: localhost:8080\r\n\r\n");
  }
);

client.on("data", function(data) {
  console.log(data.toString("utf-8", 0, data.length));
});

我得到以下回复:

HTTP/1.1 200 OK
Date: Thu, 20 May 2021 22:45:26 GMT
Server: Apache/2.4.25 (Win32) PHP/5.6.30
Last-Modified: Thu, 20 May 2021 20:14:17 GMT
ETag: "1f-5c2c89677c5c7"
Accept-Ranges: bytes
Content-Length: 31
Content-Type: application/json

{"message":"message from json"}

此响应立即显示在控制台中。但由于它来自“数据”事件,我猜如果响应更大,它会分块出现。

因此,我还使用以下内容进行了测试(其他条件相同):

var data="";
client.on("data", function(d) {
    console.log("1");
    data += d.toString("utf-8", 0, d.length);
});

client.on("end", function(d) {
  console.log(data);
});

认为我可以使用事件“结束”来确保在做其他事情之前我拥有完整的数据集。我猜这是可行的,但出乎意料的是“1”立即显示,但在“结束”事件被触发之前需要几秒钟。

问题 1)为什么与上次执行的“数据”事件相比,“结束”事件有这样的延迟?有更好的方法吗?

问题 2)具有上述响应,其中包含一堆标题以及内容正文。提取身体部位的最佳方法是什么?

请注意,我想使用 net 库而不是 fetch 或 http 库(或任何其他抽象)来执行此操作。我希望它尽可能快。

标签: node.jshttp

解决方案


我只能看到两个手动完成所有工作的正当理由:

  • 极速需求 => 那么您应该考虑使用“go”或其他编译语言
  • 学习(总是很有趣)我建议你使用 express 或任何其他 npm 包来处理所有事情,而无需重新发明轮子。

但是,我会帮助您了解我所知道的:第一件事是正确解码 ut8 字符串。您需要使用 string_decoder,因为如果数据块不完整,并且您调用 data.toString('utf8'),您将附加一个损坏的字符。不经常发生但很难调试。

这是一种有效的方法:

const { StringDecoder } = require('string_decoder');
var decoder = new StringDecoder('utf8');
var stdout = '';
stream.on('data', (data) => {
    stdout += decoder.write(data);
});

https://blog.raphaelpiccolo.com/post/827

然后回答你的问题:

  1. 我不知道,可能与gzip有关。服务器停止连接可能很慢,或者是客户端的错。或者网络本身。我会尝试使用其他客户端/服务器来确定,然后开始分析。

  2. 您需要阅读 http 规范来处理所有边缘情况(http1/websockets/http2)。但我认为你很幸运,标题总是用双换行符与正文分开。那么如果你遍历来自流的数据,在它被逐字符解码后,你可以搜索这个模式\n\n。之后的任何东西都将是身体。我想到的一种特殊情况是保持活动状态:如果客户端和服务器处于保持活动状态,则调用之间的连接不会关闭。您可能需要解析“Content-Length”标头以了解要等待多少个字符。


推荐阅读