formdata类型参数_Golang Post Multipart/formdata

本文详细探讨了在Golang中遇到的发送multipart/form-data请求的问题,包括Content-Type、boundary和Content-Disposition的重要性。文章通过分析错误案例,解释了如何正确设置MIME类型以确保服务器能正确解析图片文件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题描述

需求是上传一张图片到我们的对象存储服务器。

对方给了接口协议

  1. post 请求

  2. Content-Type 为 multipart/form-data

  3. form-data, key = "filecontent",value = 图片内容

之前自己用 node.js 写过,几行代码搞定,以为没啥问题,结果用 Golang 遇到了坑

node.js

node.js 发送请求,只需要这几行

const options = {    method: "POST",    url: "xxxxxxxxxxxxx",    headers: {      "Content-Type": "multipart/form-data"    },    timeout: 3000,    formData: {      // key:filecontent value:stream      "filecontent": fs.createReadStream(zip_file_path)    }  };  request(options, function (err, res, body) {    if (err) {      console.log(err);    } else {      let data = JSON.parse(body);      if (data.errcode) {        console.log(data)      } else {        console.log('cdn链接:\t' + data.download_url);      }    }  });

golang

当需要在 golang 上发送这个请求的时候,就遇到了各种问题

网上搜到了一些方法,诸如,multipart.createFormFile 等等,关键是还是不对。

先看看 golang 的 net/http 包自带的方法,如何发一个 post 请求,如何设置 Content-Type

buf := new(bytes.Buffer)w := multipart.NewWriter(buf)http.NewRequest("POST", GIFT_URL, buf)contentType := w.FormDataContentType()req.Header.Set("Content-Type", contentType)

但是,你会发发现,即使你设置了你的 Content-Type 是 multipart/form-data,debug 也能看到你的 body 里面有这个文件的所有数据,但是对方服务器还是不一定能解析出来,完全看服务端的同学怎么实现、怎么解析。比如,服务器是一个对象存储系统,并且对上传的文件类型有严格判断,这样的话,大概率是错误的,为什么?

抓包看协议

先来看正确的请求

89ae56c9ffb470a3a9cdf337f3310c7e.png

再来看一个出错的golang代码的请求

deb03f0288ab4f32dd6e7e23634592bd.png

MIME

上图中可以看到,HTTP 协议之后,还带上了一个 MIME 协议。当我们的 HTTP 的 Content-Type 设置为 multipart/form-data 时,我们的请求后会跟着 MIME 协议。这是对于 HTTP 协议的扩展,通过搜资料,说是以前 HTTP 不能传送各种文件等等的东西,而 MIME 是邮件协议,对 HTTP 进行了扩展,让 HTTP 也可以传输各种文件等资源。

所以问题的本质是什么?

那既然抓包发现了 MIME,那么也很清晰的看到了 golang 发出的请求的错误原因,没有指定 MIME 的 Content-Type。Content-Type 类型很多,如下表格

类型典型示例
texttext/plain, text/html, text/css, text/javascript
image

image/gif, image/png, image/jpeg, image/bmp,

image/webp, image/x-icon, 

image/vnd.microsoft.icon

audio

audio/midi, audio/mpeg, audio/webm, 

audio/ogg, audio/wav

videovideo/webm, video/ogg
application

application/octet-stream, application/pkcs12,

application/vnd.mspowerpoint,

application/xhtml+xml, application/xml,

application/pdf

那我们上传的是图片,所以 Content-Type 为 image/xxx

神奇的 boundary 是什么

我们在抓到的包中还会看到有个叫做 boundary 的字符串,这个其实是一个分隔符,让我们能正确解析上传的文件

一个请求的具体信息大致如下

Content-Type: multipart/form-data; boundary=aBoundaryString(other headers associated with the multipart document as a whole)--aBoundaryStringContent-Disposition: form-data; name="myFile"; filename="img.jpg"Content-Type: image/jpeg(data)--aBoundaryStringContent-Disposition: form-data; name="myField"(data)--aBoundaryString(more subparts)--aBoundaryString--

每个字段/文件都被 boundary 分成单独的段,这样可以知道每个文件的范围。

Content-Disposition 又是什么

在常规的 HTTP 应答中, Content-Disposition 消息头指示回复的内容该以何种形式展示,是以内联的形式(即网页或者页面的一部分),还是以附件的形式下载并保存到本地。

Content-Disposition 作为 multipart body 中的消息头时,第一个参数总是固定不变的 form-data;附加的参数不区分大小写,并且拥有参数值,参数名与参数值用等号(=)连接,参数值用双引号括起来。参数之间用分号(;)分隔,如上图。

修改一下我们的原始代码

那其实核心原因就是 MIME 的 Content-Type 了,我们的对象存储服务器,只接受一般的图片类型,要加上图片文件的类型,否则后端无法解析,就会报错,所以代码修改如下:

header := make(textproto.MIMEHeader)header.Set("Content-Disposition", fmt.Sprintf(`form-data;name="%s";filename="%s"`,"filecontent", baseFileName))mimeType := mime.TypeByExtension(ext)header.Set("Content-Type", mimeType)

加上 MIME 的 Type 即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值