gpt4 book ai didi

node.js - Express 中的响应流在 Azure 应用服务中不起作用

转载 作者:行者123 更新时间:2023-12-03 12:17:47 32 4
gpt4 key购买 nike

我正在尝试使用 Azure 应用服务托管的 NodeJS Express 服务器将响应流式传输到我的客户端。但是,我注意到它并不是真正的流式传输,而是尝试将响应作为一个整体发送。当响应大小很大(>50MB)时,客户端会收到内部服务器错误,但服务器不会抛出错误。

此外,当我在 Docker 中运行服务器时( Node 图像:10.22.0-alpine3.9),我看到客户端即使对于巨大的响应也会以流的形式获取响应。 (这是我真正需要的行为)

我的web.config文件如下。

<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<handlers>
<add name="iisnode" path="server.js" verb="*" modules="iisnode" responseBufferLimit="0"/>
</handlers>
<iisnode flushResponse="true" />
...
</system.webServer>
</configuration>

这是对我的程序的作用的一个小解释。

我有一个外部 API,它返回类似于以下内容的对象。

{
"title":"Test Title",
"lastBuildDate":"1597981114347",
"items":[
{
id: 'item1',
value: 'value1'
},
{
id: 'item2',
value: 'value2'
},
...
[
}

我只想过滤 items 数组中的元素并将其发送到客户端。客户端应该得到如下响应。

[
{
id: 'item1',
value: 'value1'
},
{
id: 'item2',
value: 'value2'
},
...
[

有时这个对象太大(>50MB),因此,我将响应作为流发送,以避免在我的服务器中使用太多的缓冲内存。下面是我用来传输响应的代码。

const https = require('https');
const { withParser } = require('stream-json/filters/Pick');
const { streamArray } = require('stream-json/streamers/StreamArray');
const { chain } = require('stream-chain');

exports.getStreamResponse = async function (req, res) {
const options = {
hostname,
port,
path,
method: 'GET',
};

return new Promise((resolve, reject) => {
https.request(options, (dataStream) => {
const pipeline = chain([
dataStream,
withParser({ filter: 'items' }),
streamArray()
]);

res.write("[");

let separator = '';

pipeline.on('data', data => {
res.write(separator + JSON.stringify(data.value));
if (!separator) {
separator = ',';
}
});

pipeline.on('end', () => {
res.write("]");
res.end();
resolve();
});

pipeline.on('error', (error) => {
reject(error);
});
});
})
};

我还注意到,如果我编写如下代码,我总是会得到流响应。但是,响应的格式不符合需要。

https.request(options, (dataStream) => {
dataStream.pipe(res);
});

最佳答案

就像我在问题的后半部分中描述的那样,直接将 res (我对客户端的响应)传输到 dataStream (我从外部获取的数据流) API)允许毫无问题地进行流式传输。

扩展相同的行为,我创建了一个 Readable 流,它相当于我应该发送给客户端的响应。然后我将它通过管道传输到 res 并且它起作用了。

这是我的解决方案。

const https = require('https');
const { withParser } = require('stream-json/filters/Pick');
const { streamArray } = require('stream-json/streamers/StreamArray');
const { chain } = require('stream-chain');
const { Readable } = require('stream');

exports.getStreamResponse = async function (req, res) {
const options = {
hostname,
port,
path,
method: 'GET',
};

return new Promise((resolve, reject) => {
https.request(options, (dataStream) => {
const pipeline = chain([
dataStream,
withParser({ filter: 'items' }),
streamArray()
]);

// create a readable stream to collect data from response
const readable = new Readable({
// this empty method is to avoid 'ERR_METHOD_NOT_IMPLEMENTED'
// error when read method is called while there is no data in the
// readable stream
read(size) { }
});

let separator = '';

readable.pipe(res);
readable.push("[");

pipeline.on('data', data => {
readable.push(separator + JSON.stringify(data.value));
if (!separator) {
separator = ',';
}
});

pipeline.on('end', () => {
readable.push("]");
readable.push(null);
resolve();
});

pipeline.on('error', reject);
});
})
};

但是,我注意到这个解决方案比我遇到问题的解决方案需要更多的内存。可能是因为我正在创建一个多余的可读流。

关于node.js - Express 中的响应流在 Azure 应用服务中不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63555610/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com