将大型 JSON 负载发送到 Web 服务的方法
Approach to send a large JSON payload to a web service
考虑一个小型 Go 应用程序,该应用程序读取一个 2GB+ 的大型 JSON 文件,将 JSON 数据编组到一个结构中,并将 JSON 数据发布到 Web 服务端点。
接收负载的 Web 服务更改了其功能,现在每个负载的限制为 25MB。使用 Go 解决此问题的最佳方法是什么?我想到了以下方法,但我不确定这是最好的方法:
- 创建一个函数将大 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 对象可以拆分成更小的部分。从这点来说,我可以提出几个方案。
使用 HTTP 请求
优点:在 client-side.
上实现起来非常简单
缺点:发出数百个 HTTP 请求可能会很慢。您还需要处理超时 - 这是额外的复杂性。
使用 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
}
}
}
考虑一个小型 Go 应用程序,该应用程序读取一个 2GB+ 的大型 JSON 文件,将 JSON 数据编组到一个结构中,并将 JSON 数据发布到 Web 服务端点。
接收负载的 Web 服务更改了其功能,现在每个负载的限制为 25MB。使用 Go 解决此问题的最佳方法是什么?我想到了以下方法,但我不确定这是最好的方法:
- 创建一个函数将大 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 对象可以拆分成更小的部分。从这点来说,我可以提出几个方案。
使用 HTTP 请求
优点:在 client-side.
上实现起来非常简单缺点:发出数百个 HTTP 请求可能会很慢。您还需要处理超时 - 这是额外的复杂性。
使用 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
}
}
}