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

huangapple go评论73阅读模式
英文:

Approach to send a large JSON payload to a web service

问题

考虑一个小的Go应用程序,它读取一个大于2GB的JSON文件,将JSON数据编组为一个结构体,并将JSON数据POST到一个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()
}
英文:

Consider a small Go application that reads a large JSON file 2GB+, marshals the JSON data into a struct, and POSTs the JSON data to a web service endpoint.

The web service receiving the payload changed its functionality, and now has a limit of 25MB per payload. What would be the best approach to overcome this issue using Go? I've thought of the following, however I'm not sure it is the best approach:

  1. Creating a function to split the large JSON file into multiple smaller ones (up to 20MB), and then iterate over the files sending multiple smaller requests.

Similar function to the one being used to currently send the entire JSON payload:

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()
}

答案1

得分: 0

由于服务器端可以逐步处理数据,我假设大的JSON对象可以分割成较小的部分。从这一点出发,我可以提出几个选项。

  1. 使用HTTP请求

    优点:在客户端实现相当简单。

    缺点:进行数百个HTTP请求可能会很慢。您还需要处理超时 - 这增加了复杂性。

  2. 使用WebSocket消息

    如果接收方支持WebSocket,逐步流程如下:

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

    这种解决方案可能更高效,因为您不需要每次发送消息时都连接和断开服务器,就像使用HTTP一样。

然而,这两种解决方案都假设您需要在服务器端组装所有部分。例如,您可能需要随数据一起发送一个关联ID,以让服务器知道您当前正在发送的文件,以及一个特定的文件结束消息,以让服务器知道文件何时结束。在WebSocket服务器的情况下,如果相关,您可以假设整个文件在单个连接会话期间发送完毕。

英文:

As the server-side can process data progressively, I assume that the large JSON object can be split into smaller pieces. From this point, I can propose several options.

  1. Use HTTP requests

    Pros: Pretty simple to implement on the client-side.

    Cons: Making hundreds of HTTP requests might be slow. You will also need to handle timeouts - this is additional complexity.

  2. Use WebSocket messages

    If the receiving side supports WebSockets, a step-by-step flow will look like this:

    • Split the input data into smaller pieces.
    • Connect to the WebSocket server.
    • Start sending messages with the smaller pieces till the end of the file.
    • Close connection to the server.

    This solution might be more performant as you won't need to connect and disconnect from the server each time you send a message, as you'd do with HTTP.

However, both solutions suppose that you need to assemble all pieces on the server-side. For example, you would probably need to send along with the data a correlation ID to let the server know what file you are sending right now and a specific end-of-file message to let the server know when the file ends. In the case of the WebSocket server, you could assume that the entire file is sent during a single connection session if it is relevant.

答案2

得分: 0

你可以将输入分成多个部分,然后逐个发送:

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
        }
        // 在这里,obj 包含数组的一个元素。你可以将其发送到服务器。
        if !dec.More() {
            break
        }
    }
}
英文:

You can break the input into chunks and send each piece individually:

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
		}
	}
}

huangapple
  • 本文由 发表于 2022年2月5日 00:01:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/70989334.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定