将大型 JSON 负载发送到 Web 服务的方法

Approach to send a large JSON payload to a web service

考虑一个小型 Go 应用程序,该应用程序读取一个 2GB+ 的大型 JSON 文件,将 JSON 数据编组到一个结构中,并将 JSON 数据发布到 Web 服务端点。

接收负载的 Web 服务更改了其功能,现在每个负载的限制为 25MB。使用 Go 解决此问题的最佳方法是什么?我想到了以下方法,但我不确定这是最好的方法:

  1. 创建一个函数将大 JSON 文件拆分为多个较小的文件(最多 20MB),然后遍历文件发送多个较小的请求。

与当前用于发送整个 JSON 有效载荷的函数类似的函数:

func sendDataToService(data StructData) {
    payload, err := json.Marshal(data)
    if err != nil {
        log.Println("ERROR:", err)
    }

    request, err := http.NewRequest("POST", endpoint, bytes.NewBuffer(payload))
    if err != nil {
        log.Println("ERROR:", err)
    }

    client := &http.Client{}
    response, err := client.Do(request)
    log.Println("INFORMATIONAL:", request)
    if err != nil {
        log.Println("ERROR:", err)
    }
    defer response.Body.Close()
}

由于 server-side 可以逐步处理数据,我假设大的 JSON 对象可以拆分成更小的部分。从这点来说,我可以提出几个方案。

  1. 使用 HTTP 请求

    优点:在 client-side.

    上实现起来非常简单

    缺点:发出数百个 HTTP 请求可能会很慢。您还需要处理超时 - 这是额外的复杂性。

  2. 使用 WebSocket 消息

    如果接收方支持 WebSockets,step-by-step 流程将如下所示:

    • 将输入数据拆分成更小的部分。
    • 连接到 WebSocket 服务器。
    • 开始发送包含较小部分的消息,直到文件结束。
    • 关闭与服务器的连接。

    此解决方案的性能可能更高,因为您不需要像使用 HTTP 那样在每次发送消息时都连接和断开与服务器的连接。

但是,这两种解决方案都假设您需要 assemble server-side 上的所有棋子。例如,您可能需要连同数据一起发送一个 关联 ID 让服务器知道您现在发送的是什么文件以及一个特定的 end-of-file message 让服务器知道文件何时结束。对于 WebSocket 服务器,如果相关,您可以假设整个文件是在单个连接会话期间发送的。

您可以将输入分成块并单独发送每个块:

dec := json.NewDecoder(inputStream)
tok, err := dec.Token()
if err != nil {
    return err
}
if tok == json.Delim('[') {
    for {
        var obj json.RawMessage
        if err := dec.Decode(&obj); err != nil {
            return err
        }
        // Here, obj contains one element of the array. You can send this
        // to the server.
        if !dec.More() {
            break
        }
    }
}