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

如何修改Go语言文件发送函数,替换application/octet-stream为正确Content-Type

解决Go语言文件上传时Content-Type被设为application/octet-stream的问题

原代码核心问题

  1. 重复请求逻辑:循环内同时通过multipart.Writer构建批量文件请求,又调用sendFileToURL单独发送每个文件,逻辑冗余且冲突
  2. CreateFormFile的默认行为:该方法会强制将文件部分的Content-Type设为application/octet-stream,覆盖原文件的头部信息
  3. 错误的单文件上传方式:sendFileToURL直接将文件内容作为POST请求体发送,未封装为标准的multipart/form-data格式,不符合常规文件上传接口的解析要求

修正后的代码

func (s *FileService) SentFileToCreate(ctx context.Context, userUUID string, form *multipart.Form) (*models.File, error) {
    var fileResult = &models.File{}
    now := time.Now()

    textValue := form.Value["text"][0]
    files := form.File["files"]

    id, _ := s.repo.GetUserIdByUuid(ctx, userUUID)
    fileResult.Text = textValue
    fileResult.CreatedStamp = &now
    fileResult.AuthorID = id

    var mediaL []*models.File

    body := &bytes.Buffer{}
    writer := multipart.NewWriter(body)
    defer writer.Close()

    url := "http://0.0.0.0:9090/api/v1/file/upload"

    // 添加text字段到multipart表单
    if err := writer.WriteField("text", textValue); err != nil {
        return nil, err
    }

    for _, file := range files {
        media := &models.File{
            FileName:    file.Filename,
            ContentType: file.Header.Get("Content-Type"),
        }
        mediaL = append(mediaL, media)

        // 手动构建文件部分的MIME头部,保留原Content-Type
        partHeader := make(textproto.MIMEHeader)
        partHeader.Set("Content-Disposition", fmt.Sprintf(`form-data; name="files"; filename="%s"`, file.Filename))
        partHeader.Set("Content-Type", file.Header.Get("Content-Type"))

        part, err := writer.CreatePart(partHeader)
        if err != nil {
            return nil, err
        }

        fileContent, err := file.Open()
        if err != nil {
            return nil, err
        }
        _, err = io.Copy(part, fileContent)
        fileContent.Close() // 避免defer在循环内累积导致资源泄漏
        if err != nil {
            return nil, err
        }
    }

    req, err := http.NewRequest("POST", url, body)
    if err != nil {
        return nil, err
    }

    // 设置正确的multipart表单Content-Type,包含boundary
    req.Header.Set("Content-Type", writer.FormDataContentType())

    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    fmt.Println("Status:", resp.Status)

    return s.repo.SaveFile(ctx, fileResult)
}

// 移除原sendFileToURL函数,因为已统一用multipart.Writer处理上传逻辑

关键修改说明

  • 移除冗余的sendFileToURL:统一通过multipart.Writer构建包含所有字段和文件的完整请求体,避免重复请求
  • 手动创建表单文件部分:用writer.CreatePart替代CreateFormFile,手动设置Content-Disposition和原文件的Content-Type,确保接收端能识别正确的文件类型
  • 修复资源泄漏:循环内打开文件后立即关闭,避免defer在循环中累积导致大量文件句柄未及时释放
  • 添加text字段到表单:原代码中只处理了文件,但未将text字段加入到最终发送的multipart表单中,补充该逻辑保证请求参数完整

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 21:23:18