来自 Node 的带有分块响应流的 Axios 请求

Posted

技术标签:

【中文标题】来自 Node 的带有分块响应流的 Axios 请求【英文标题】:Axios request with chunked response stream from Node 【发布时间】:2020-03-16 14:55:11 【问题描述】:

我在 React 中有一个客户端应用程序,在 Node 中有一个服务器(使用 Express)。 在服务器端,我有一个类似以下的端点(不是真正的端点,只是我在做什么的一个想法):

function endpoint(req, res) 
   res.writeHead(200, 
        'Content-Type': 'text/plain',
        'Transfer-Encoding': 'chunked'
      );

   for(x < 1000)
      res.write(some_string + '\n');
      wait(a_couple_of_seconds); // just to make process slower for testing purposes
   

   res.end();

这是完美的,我的意思是,当我调用这个端点时,我会收到包含所有 1.000 行的整个流。

问题是我无法设法按块获取这些数据(对于每个“写入”或一堆“写入”),以便在我收到它们后立即在前端显示..(想想在我从端点调用中获取行后立即显示行的表)

在前端,我使用 Axios 调用 API,代码如下:

async function getDataFromStream(_data): Promise<any> 
    const  data, headers  = await Axios(
        url: `http://the.api.url/endpoint`,
        method: 'GET',
        responseType: 'stream',
        timeout: 0,
    );

    // this next line doesn't work. it says that 'on' is not a function
    data.on('data', chunk => console.log('chunk', chunk)); 
    // data has actually the whole response data (all the rows)

    return Promise.resolve();

问题是 Axios 调用在调用服务器上的“res.end()”之后返回整个数据对象,但我需要在服务器开始发送带有行的块时立即获取数据(在每次 res.write 或服务器认为已准备好发送一些块时)。

我也尝试过不使用 await 并在 axios 调用的 'then()' 处获取 promise 的值,但这是相同的行为,'data' 值与所有 '一旦服务器执行 'res.end()'

那么,我在这里做错了什么?也许这对于 Axios 或 Node 是不可能的,我应该使用 websockets 之类的东西来解决它。 任何帮助都将不胜感激,因为我阅读了很多但还没有找到可行的解决方案。

【问题讨论】:

【参考方案1】:

对于任何对此感兴趣的人,我最终做的是以下内容:

在客户端,我使用了允许处理下载进度事件的 Axios onDownloadProgress 处理程序。

所以,我实现了这样的东西:

function getDataFromStream(_data): Promise<any> 
    return Axios(
        url: `http://the.api.url/endpoint`,
        method: 'GET',
        onDownloadProgress: progressEvent => 
           const dataChunk = progressEvent.currentTarget.response;
           // dataChunk contains the data that have been obtained so far (the whole data so far).. 
           // So here we do whatever we want with this partial data.. 
           // In my case I'm storing that on a redux store that is used to 
           // render a table, so now, table rows are rendered as soon as 
           // they are obtained from the endpoint.
        


    ).then(( data ) => Promise.resolve(data));    


【讨论】:

dataChunk 包含到目前为止的所有块,因为我已经处理了以前的块,所以我只需要“新”块。有什么方法可以获取新的块? 您是否可以控制服务器上的数据格式?如果是这样,您可以创建类似管道分隔的字符串,客户端可以解析该字符串以获取“最新”事件。下面是我如何解析看起来像 'event1|event2|event3|...' 的数据的示例: return axios.post('some/end/point', payload, onDownloadProgress: (progressEvent) => //RegEx获取 | 分隔字符串中的最后一项// const message = /\|([^|]+)\|$/.exec(progressEvent.currentTarget.response); EventBus.$emit('show-feedback', message ? 消息[1] : '', '成功'); );

以上是关于来自 Node 的带有分块响应流的 Axios 请求的主要内容,如果未能解决你的问题,请参考以下文章

vue中axios安装及使用

禁用传输编码:在 Spring Webflux 响应中分块

如何在反应中设置来自axios的响应状态

无法捕获并记录来自 axios 请求的错误响应

如何将 map() 与来自 axios 响应的数据一起使用?

如何为来自 axios.get 的响应使用类型