Go HTTP服务器重置带有文件和文本的多部分表单上的连接

Go HTTP server resets connection on multipart form with file and text

提问人:LukeAtmi 提问时间:11/17/2023 更新时间:11/17/2023 访问量:68

问:

我一直在尝试在 Go 中设置一个 HTTP 服务器,允许用户通过 HTML 表单上传文件。出于其他原因,此表单还将具有文本输入。但是,在提交表单时,我的浏览器报告连接已重置(我尝试过使用 Firefox 和 Chromium),检查显示服务器在重置之前甚至没有到达上传端点的处理程序功能,尽管它没有崩溃。奇怪的是,当表单中的唯一输入是文件和提交时,这不会发生。

这是最小的复制品:

package main

import (
    "fmt"
    "net/http"
)

func showPage(w http.ResponseWriter, r *http.Request) {
    fmt.Fprint(w,
`<!DOCTYPE html>
<html>
    <body>
    <form enctype="multipart/form-data" action="/upload">
        <input type="file" name="file" />
        <input type="text" name="lol" />
        <input type="submit" value="upload" />
    </form>
</body>
</html>`)
}

func uploadHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Println("yay!")
    fmt.Fprint(w, "yay!")
}

func main() {
    http.HandleFunc("/", showPage)
    http.HandleFunc("/upload/", uploadHandler)

    http.ListenAndServe(":8080", nil)
}

运行上述代码并在表单 at 中提交文件应显示“yay!”页面,并在服务器控制台上打印“yay!”。相反,在提交足够大的文件(非常小的文件不会导致问题)时,连接将重置,并且控制台上不会打印任何内容。这个 5MB 的音频样本足够大,足以让我出现问题。http://localhost:8080/

如果表单中的唯一输入是文件,则出于某种原因,一切运行正常。

多部分表单数据 转到 http

评论

0赞 zerkms 11/17/2023
提供的代码按预期工作,对我来说是 100+ Mb 文件,也是提供的 mp3。
0赞 LukeAtmi 11/17/2023
我想那一定是我的机器上有问题。不过,我想知道可能是什么原因造成的。
0赞 Cerise Limón 11/17/2023
程序将忽略从 ListenAndServe 返回的错误。将 main 的最后一行更改为log.Fatal(http.ListenAndServe(":8080", nil))
0赞 LukeAtmi 11/17/2023
@CeriseLimón我知道,但是在这种情况下 ListenAndServe 不会返回,服务器会继续运行,因此检查日志是没有用的。(我已经做过了,但一无所获)
0赞 Cerise Limón 11/17/2023
“服务器甚至无法访问处理程序函数”的一个可能原因是 ListenAndServe 失败,因为另一个版本的服务器仍在 8080 上运行。日志。致命的w会抓住它。

答:

1赞 Maristela Vasco 11/17/2023 #1

处理程序不读取任何请求正文。

从处理程序返回时,当未读请求正文的大小大于 262,144 字节时,net/http 服务器将关闭连接。

客户端在尝试写入请求正文时收到连接重置。客户端在读取响应之前出错。

通过读取请求正文进行修复。鉴于您需要多部分表单,因此调用 ParseMultipartForm 是读取请求正文的最简单方法。

func uploadHandler(w http.ResponseWriter, r *http.Request) {
    if err := r.ParseMultipartForm(65535); err != nil {
        http.Error(w, "bad request", 400)
        return
    }
    fmt.Println("yay!")
    fmt.Fprint(w, "yay!")
}

评论

0赞 LukeAtmi 11/17/2023
明白了。这解释了这个问题,但如何修复/规避它呢?我认为有一种正确的方法可以做到这一点。
1赞 erik258 11/17/2023
HTTP 规范要求服务器先读取请求正文,然后才能发送响应正文。继续在请求中实现对 MultiPartForm 上传的处理。
0赞 LukeAtmi 11/17/2023
当我发现这个问题时,我实际上正在这样做。但是,由于在重置之前甚至从未调用过 uploadHandler,因此我没有机会解析表单。