【问题标题】:HTTP request is aborted after response write in Golang在 Golang 中写入响应后,HTTP 请求被中止
【发布时间】:2020-09-27 18:09:33
【问题描述】:

我在 Go 中有一个服务器来处理文件上传。这是一个遗留代码,所以我不能接触太多。

如果服务器在请求头中检测到一些错误,它应该中断上传,并且它应该向客户端返回一条消息,指出出现了问题。

处理函数类似于以下内容:


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

            // Check the header. Could be more than one.
            if r.Header.Get("key") == "not as expected" {
                w.WriteHeader(500)
                w.Write("key is wrong")
                return
            }

        //handle the file upload

}

标头检查只是说明问题的一个例子

服务器在写入后关闭连接并从函数中返回,即使请求没有完成(收到文件)。

在客户端 (Java) 上,当我使用带有错误值的 key 和要作为正文上传的文件发出请求时,我得到了一个损坏的管道异常并且它无法正确处理响应。 实际上我无法触摸客户端代码。

服务器端有办法等到请求结束后再关闭连接吗?

【问题讨论】:

  • 您在Write 之后返回,因此请求 完成。如果您想阅读请求正文,请确保您阅读了请求正文。

标签: file go upload


【解决方案1】:

在 Java 客户端上看到的“管道损坏”错误¹表明客户端坚持在尝试从服务器读取响应之前发送其请求的有效负载(正文)。

在 HTTP/1.1(和 1.0)中,客户端 是正确的: 规范中没有任何内容说客户端必须期望服务器在整个请求之前响应 - 即标头 正文,如果有的话,——被提交。

在您的特定情况下,最简单的方法是将客户的主体通过管道传送到无处,然后以错误响应。一种惯用的方法是使用io/ioutil.Discard 类型:


func(w http.ResponseWriter, r *http.Request) {
    // Check the checksum header
    if r.Header.Get("key") == "not as expected" {
        _, err := io.Copy(ioutil.Discard, r.Body)
        if err != nil {
            // The client went away.
            // May be log something, then bail out.
            panic(http.ErrAbortHandler)
        }
        w.WriteHeader(500)
        w.Write("key is wrong")
        return
    }

    //handle the file upload
}

net/http.ErrAbortHandler 可用于告诉 HTTP 服务器库代码不应以正常方式执行请求。


顺便说一句,用 5xx 响应格式错误的客户端请求是不正确的,您应该使用 4xx 代替。但它是遗留代码,因此请将此作为未来发展的提示。


¹ 请参阅 send(2) manual page 中的 EPIPE

【讨论】:

    猜你喜欢
    • 2021-07-01
    • 2016-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-18
    • 2020-11-26
    • 2019-07-17
    相关资源
    最近更新 更多