You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Golang服务器转发表单上传文件至Flask服务器时request.files为空的问题及优化方案

解决Golang转发Multipart文件至Flask时request.files为空的问题

问题背景

我正在开发一个文件上传转发应用:页面表单将文件上传至Golang服务器,再由Golang服务器转发给Flask服务器处理。但遇到了一个棘手的问题:Golang能正常接收文件,可Flask端始终无法获取到文件,request.files一直为空。

初始代码

Golang服务器代码

func api_upload_model(w http.ResponseWriter, r *http.Request) {
    r.ParseMultipartForm(50 << 20)
    file, handler, err := r.FormFile("Model")
    if err != nil {
        fmt.Println("Error Retrieving the File")
        fmt.Println(err)
        return
    }
    fmt.Printf("Uploaded File: %+v\n", handler.Filename)
    fmt.Printf("File Size: %+v\n", handler.Size)
    resp, err := http.Post(*URL here*, "multipart/form-data", file)
    if err != nil {
        fmt.Println("Error Sending the File")
        fmt.Println(err)
        return
    }
    w.Header().Set("Content-Type", "text/html")
    buffer, _ := ioutil.ReadAll(resp.Body)
    _, err = w.Write(buffer)
    if err != nil {
        fmt.Println("Error Sending the File")
        fmt.Println(err)
        return
    }
}
func main() {
    router := chi.NewRouter()
    router.Post("/api/upload_model", api_upload_model)
    http.ListenAndServe(":8080", router)
}

Flask处理代码

@app.route('/upload_model', methods=['POST'])
def upload_model():
    log("Inference server", "123")
    name = request.args.get('name', None)
    if name is None:
        return "Error: bad request parameters."
    print(str(request))
    if 'file' not in request.files:
        # 我知道未将文件名设为'file',但request.files始终为空
        return "No file"
    file = request.files['file']
    if file:
        filename = secure_filename(name)
        file.save(os.path.join("data/models", name))
        return "200"

问题现象

Golang控制台能正常输出文件信息:Uploaded File: 1.jpg和File Size: 114940,说明文件接收环节没有问题。但Flask端打印的请求为<Request 'http://*URL here*/upload_model?name=1.jpg' [POST]>,且request.files始终为空,完全无法获取到上传的文件内容。

问题根源

你最初的Golang代码犯了一个典型错误:当用r.FormFile("Model")取出单个文件流后,直接将这个流作为http.Post的请求体发送给Flask。但multipart/form-data类型的请求并非单纯的文件内容,它需要包含边界分隔符、字段名、文件名等元数据信息。仅传递文件内容的话,Flask无法识别这是一个合法的文件上传请求,自然解析不出request.files中的内容。

正确解决方案

最简洁高效的办法是不解析原请求的multipart内容,直接将整个请求原封不动转发给Flask,这样能完整保留原始请求的multipart/form-data结构,让Flask正常解析文件。修改后的Golang代码如下:

func api_upload_model(w http.ResponseWriter, r *http.Request) {
    // 基于原始请求创建转发请求,不解析multipart表单
    proxyReq, err := http.NewRequest(r.Method, *URL here*, r.Body)
    if err != nil {
        fmt.Println("创建转发请求失败:", err)
        http.Error(w, "服务器内部错误", http.StatusInternalServerError)
        return
    }

    // 复制原始请求的所有请求头,尤其是Content-Type(包含multipart边界)
    proxyReq.Header = make(http.Header)
    for key, values := range r.Header {
        proxyReq.Header[key] = append([]string{}, values...)
    }

    // 发送请求到Flask服务器
    client := &http.Client{}
    resp, err := client.Do(proxyReq)
    if err != nil {
        fmt.Println("转发请求到Flask失败:", err)
        http.Error(w, "转发请求失败", http.StatusBadGateway)
        return
    }
    defer resp.Body.Close()

    // 将Flask的响应原样返回给客户端
    w.Header().Set("Content-Type", resp.Header.Get("Content-Type"))
    w.WriteHeader(resp.StatusCode)
    _, err = io.Copy(w, resp.Body)
    if err != nil {
        fmt.Println("返回响应失败:", err)
    }
}

func main() {
    router := chi.NewRouter()
    router.Post("/api/upload_model", api_upload_model)
    http.ListenAndServe(":8080", router)
}

额外提示

这种转发方式不仅解决了文件解析问题,还避免了多余的multipart解析和重新构建工作,效率更高。另外需要注意:

  • 务必复制原始请求的所有头部,尤其是Content-Type,它包含的multipart边界是Flask正确识别文件的关键。
  • 如果需要给Flask请求添加额外参数(比如代码中的name),可以在创建proxyReq时修改URL的查询参数部分。

内容的提问来源于stack exchange,提问作者Dmitry

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 15:52:43