You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Express发送对象数组?前后端方案抉择

方案可行性与弊端分析

客户端多请求方案的可行性

这个方案完全可行。服务端提供单集合查询接口,客户端并行发起多个请求对应不同关键词的集合查询,这种模式在实际开发中是常见的实现方式。

存在的弊端

  • 请求开销与并发限制问题
    你需要发起11个HTTP请求,而浏览器对同一域名的并发请求数有默认限制(通常为6-8个),超出的请求会排队等待,反而拖慢整体数据获取速度。同时每个HTTP请求都包含握手、头部传输等额外开销,大量请求会增加客户端和服务端的资源消耗。
  • 客户端逻辑复杂度提升
    需要在客户端管理多个请求的状态,处理每个请求的成功/失败情况,还要合并返回数据。如果某一个请求失败,需要额外处理重试或错误提示逻辑,增加前端代码的维护成本。
  • 服务端负载放大
    原本一次请求就能完成的查询变为11次,服务端需要处理更多的HTTP连接、解析更多请求参数,MongoDB也会收到更多查询请求,在高并发场景下会显著放大服务端的负载压力。
  • 跨域额外开销
    若前后端不在同一域名下,每个请求都会触发跨域预检(OPTIONS请求),进一步增加请求延迟和资源消耗。

原后端方案的改进思路

你想要的分块返回有效JSON+实时返回是可以实现的,无需改成客户端多请求模式,只需调整后端输出逻辑:

方法1:采用JSON Lines格式流式返回

将每个查询结果作为独立JSON对象,用换行符分隔,客户端可逐行解析:

async function retrieve_multiple(req, res) {
    const search_string = req.query.search_string;
    const limit = req.query.limit;

    const keywords = [
        'are', 'can', 'did', 'does', 'how', 'should',
        'what', 'when', 'which', 'who', 'why'
    ];

    // 设置响应头,声明为JSON Lines流
    res.set({
        'Access-Control-Allow-Origin': '*',
        'Content-Type': 'application/jsonl',
        'Transfer-Encoding': 'chunked'
    });

    // 逐个查询并实时返回结果
    for (const keyword of keywords) {
        try {
            const data = await models.getArticle(keyword, search_string, limit);
            res.write(JSON.stringify(data) + '\n');
        } catch (err) {
            res.write(JSON.stringify({ error: err.message, keyword }) + '\n');
        }
    }

    res.end();
}

客户端解析逻辑示例:

async function fetchStreamData() {
    const response = await fetch('/api/retrieve-multiple?search_string=xxx&limit=10');
    const reader = response.body.getReader();
    const decoder = new TextDecoder();
    let buffer = '';

    while (true) {
        const { done, value } = await reader.read();
        if (done) break;

        buffer += decoder.decode(value, { stream: true });
        const lines = buffer.split('\n');
        buffer = lines.pop(); // 保留未完成的最后一行

        for (const line of lines) {
            if (!line) continue;
            const data = JSON.parse(line);
            // 处理单个数据块
            console.log('接收数据:', data);
        }
    }
}

方法2:使用Server-Sent Events(SSE)

SSE是专门用于服务端向客户端推送事件流的标准方案,更适合实时场景:

async function retrieve_multiple(req, res) {
    const search_string = req.query.search_string;
    const limit = req.query.limit;

    const keywords = [
        'are', 'can', 'did', 'does', 'how', 'should',
        'what', 'when', 'which', 'who', 'why'
    ];

    // 设置SSE响应头
    res.set({
        'Access-Control-Allow-Origin': '*',
        'Content-Type': 'text/event-stream',
        'Cache-Control': 'no-cache',
        'Connection': 'keep-alive'
    });

    // 逐个查询并推送结果
    for (const keyword of keywords) {
        try {
            const data = await models.getArticle(keyword, search_string, limit);
            res.write(`data: ${JSON.stringify(data)}\n\n`);
            await new Promise(resolve => res.flushHeaders(resolve)); // 强制刷新发送数据
        } catch (err) {
            res.write(`data: ${JSON.stringify({ error: err.message, keyword })}\n\n`);
        }
    }

    // 发送结束事件
    res.write('event: close\ndata: all done\n\n');
    res.end();
}

客户端监听逻辑:

const eventSource = new EventSource('/api/retrieve-multiple?search_string=xxx&limit=10');

eventSource.onmessage = (event) => {
    const data = JSON.parse(event.data);
    console.log('接收数据:', data);
};

eventSource.addEventListener('close', () => {
    console.log('所有数据接收完成');
    eventSource.close();
});

eventSource.onerror = (err) => {
    console.error('SSE错误:', err);
    eventSource.close();
};

内容的提问来源于stack exchange,提问作者Muhammad Yahya Warraich

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 14:25:25