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

使用fasthttp POST提交multipart/form-data遇unexpected EOF错误求助

multipart/form-data 请求异常:unexpected EOF 问题修复

错误原因

核心问题是multipart.Writer.Close()的调用时机错误。multipart.Writer在关闭时会自动写入multipart请求的结束边界分隔符,原代码中先将bodyBuffer的内容设置到请求,之后才关闭writer,导致请求体缺少了这个关键的结束标记,服务器解析时因数据不完整抛出unexpected EOF。另外,writeFilesData中打开的文件未关闭,存在资源泄漏风险。

修复方案

  1. 调整bodyWriter.Close()的执行顺序:在写完所有字段和文件后,立即关闭writer,确保bodyBuffer包含完整的multipart数据(包括结束边界)。
  2. 关闭writer后,再将bodyBuffer的内容设置到请求体中。
  3. 在writeFilesData中添加文件关闭逻辑,使用defer file.Close()确保文件资源被释放。

修复后的完整代码

type FastHttpRestClient struct {
    client *fasthttp.Client
}

func (c *FastHttpRestClient) PostForm(request Request) ([]byte, error) {
    bodyBuffer := &bytes.Buffer{}
    bodyWriter := multipart.NewWriter(bodyBuffer)

    req := fasthttp.AcquireRequest()
    defer fasthttp.ReleaseRequest(req)

    // 设置请求头
    if request.Headers != nil {
        for k, v := range request.Headers {
            req.Header.Set(k, v)
        }
    }

    // 添加表单字段
    if request.FormData != nil {
        err := writeFieldsData(bodyWriter, request.FormData)
        if err != nil {
            return nil, err
        }
    }

    // 添加文件字段
    if request.FileFields != nil {
        err := writeFilesData(bodyWriter, request.FileFields)
        if err != nil {
            return nil, err
        }
    }

    // 关键修复:先关闭writer,确保写入结束边界
    err := bodyWriter.Close()
    if err != nil {
        return nil, err
    }

    // 设置请求信息
    req.Header.SetMethod(fasthttp.MethodPost)
    req.SetRequestURI(request.URL)
    req.SetBody(bodyBuffer.Bytes())
    req.Header.Set("Content-Type", bodyWriter.FormDataContentType())

    resp := fasthttp.AcquireResponse()
    defer fasthttp.ReleaseResponse(resp)

    if err := c.client.Do(req, resp); err != nil {
        return nil, err
    }

    return resp.Body(), nil
}

func writeFieldsData(bodyWriter *multipart.Writer, fields map[string]string) error {
    for k, v := range fields {
        fieldWriter, err := bodyWriter.CreateFormField(k)
        if err != nil {
            return err
        }
        _, err = fieldWriter.Write([]byte(v))
        if err != nil {
            return err
        }
    }
    return nil
}

func writeFilesData(bodyWriter *multipart.Writer, fileFields map[string][]*multipart.FileHeader) error {
    for fieldName, fileHeaders := range fileFields {
        for _, fileHeader := range fileHeaders {
            fileWriter, err := bodyWriter.CreateFormFile(fieldName, fileHeader.Filename)
            if err != nil {
                return err
            }
            file, err := fileHeader.Open()
            if err != nil {
                return err
            }
            // 修复:添加defer确保文件关闭
            defer file.Close()
            _, err = io.Copy(fileWriter, file)
            if err != nil {
                return err
            }
        }
    }
    return nil
}

关键修改点说明

  • 将bodyWriter.Close()移到了写入所有字段和文件之后、设置请求体之前,确保bodyBuffer包含完整的multipart数据。
  • 在writeFilesData中为打开的文件添加了defer file.Close(),避免文件资源泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 16:02:46