Correct way to notify http client of error after partial response has been sent in golang http

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

Correct way to notify http client of error after partial response has been sent in golang http

问题

如果在向客户端写入流式响应时发生错误,对于HTTP服务器来说,正确的行为是什么?客户端已经收到了状态码200,所以它认为一切正常。服务器是否仍然可以以某种方式终止连接,通知客户端发生了错误,或者应该在响应体中返回一些内容?

我正在从数据库中流式传输许多行数据,所以我希望在发送给客户端之前不要进行批处理。

以下是一个使用Go语言的示例:

func streamingHandler(s ServerSettings, db *sql.DB) http.Handler {

	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

		w.Header().Set("Content-Type", "application/json-seq")

		w.Header().Set("Access-Control-Allow-Origin", "*")

		_, err = fmt.Fprintf(w, "\u001E[1,2,3]\n", item)

		if err != nil {
			http.Error(w, err.Error(), 500)
			return
		}

		_, err = fmt.Fprintf(w, "\u001E[1,2,3]\n", item)

        // 错误可能来自Fprintf或数据库错误。

		// 如果在这里发生错误会发生什么...客户端已经收到了头部和一些响应

		if err != nil {
			http.Error(w, err.Error(), 500)
			return
		}
		... 
		等等
	})

}
英文:

What is the correct behaviour for an http server if an error occurs while writing a streaming response to the client. The client has already received status code 200 so it thinks it is okay. Can the server still terminate the connection in such a way to notify the client that an error occurred or should it return something in the response body?

I am streaming many rows from a database so I would prefer not to batch before sending to client.

An example in golang:

func streamingHandler(s ServerSettings, db *sql.DB) http.Handler {

	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

		w.Header().Set("Content-Type", "application/json-seq")

		w.Header().Set("Access-Control-Allow-Origin", "*")

		_, err = fmt.Fprintf(w, "\u001E[1,2,3]\n", item)

		if err != nil {
			http.Error(w, err.Error(), 500)
			return
		}

		_, err = fmt.Fprintf(w, "\u001E[1,2,3]\n", item)

        //  the error could be from Fprintf or a database error.

		//  What happens if error occurs here.. the client has already received header and some response

		if err != nil {
			http.Error(w, err.Error(), 500)
			return
		}
		... 
		etc
	})

}

答案1

得分: 2

我很抱歉,你需要在协议之上添加一个协议。
比如使用ajax,在自己的OK/Continue/Abort状态消息中发送短的json响应。

HTTP中没有处理这个的方法(在客户端到服务器端有一个100-Continue的方法,实现得很糟糕,而且不适用于服务器到客户端),除非可能发送分块响应并且永远不发送最后一个分块(这样整个响应将超时)。

使用ajax解决方案,您还可以在结束之前开始显示结果。

管理自己的HTTP块通常是最简单的解决方案,例如文件上传器,它们将使用js将文件拆分为块,并在服务器端重新组合文件。

试图管理反向代理或代理在大型HTTP消息通信中可能注入的所有混乱(请考虑到直到最近,Nginx反向代理不会流式传输响应,并使用缓冲消息)。

英文:

I'm afraid you'll have to add a protocol upon the protocol.
Like using ajax, sending short json responses with your own OK/Continue/Abort status messages.

There is nothing in HTTP to handle that (there is something with the 100-Continue in client to server, badly implmented and not made for server to client), unless maybe sending chunked responses and never sending the last chunk (so the whole response will timeout).

With the ajax solution you'll also be able to start showing the results before the end.

Managing you own chunks upon HTTp is usually the simpliest solution, see for exampe the file uploaders, they will split files in chunks using js and recompose the file server-side.

Trying to manage all the mess that a reverse proxy or a proxy could inject in your big HTTP messages communications (think that until recently Nginx reverse proxy would not stream responses, and use a buffered message).

huangapple
  • 本文由 发表于 2016年2月24日 18:08:19
  • 转载请务必保留本文链接:https://go.coder-hub.com/35599050.html
匿名

发表评论

匿名网友

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

确定