使用http上传文件 - chris-wangkk/myWiki GitHub Wiki

一个http表单中的enctype有如下几种: application/x-www-urlencoded(默认情况) multipart/form-data text-plain 当表单使用 POST 请求时,数据会被以某种编码(默认使用 x-www-urlencoded 方式)到 Body 中;而若采用 GET 请求,则是附在url链接后来发送(由于 GET 请求只支持 ASCII 字符集,因此要发送更大字符集的内容,只能用 POST 方式) application/x-www-urlencoded 编码格式=ASCII ,若form中传递的是二进制等 Media Type 类型的数据,此时会将其编码转换成ASCII类型(一个non-ASCII字符,需要用3个ASCII字符来表示),因此若要发送大量的二进制数据,采用 application/x-www-urlencoded 就低效了。因此,最好使用 multipart/form-data 格式

通过HTTP向服务器发送POST请求提交数据,是通过form表单形式提交的 <form method="post" action="http://w.sohu.com"> <input type="text" name="txt1"> <input type="text" name="txt2"> <input type="submit" value="Submit"> </form> 提交时向服务器的请求中携带如下数据: Content-Type:application/x-www-form-urlencoded

txt1=aaa&txt2=bbb

最早的 HTTP POST 是不支持文件上传的,而后IETF出台了rfc1867用以支持文件上传:Content-Type 的类型扩充了multipart/form-data 用以支持向服务器发送二进制数据 <form method="post" action="http://w.sohu.com" enctype="multipart/form-data"> <input type="text" name="txt1"> <input type="text" name="txt2"> <input type="file" name="txt3"> <input type="submit" value="Submit"> </form> 提交时向服务器的请求中携带如下数据: Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryW40eoeeGdUtIafwW

------WebKitFormBoundaryW40eoeeGdUtIafwW Content-Disposition: form-data; name="txt1"

aaa ------WebKitFormBoundaryW40eoeeGdUtIafwW Content-Disposition: form-data; name="txt2"

bbb ------WebKitFormBoundaryW40eoeeGdUtIafwW Content-Disposition: form-data; name="txt3"; filename="old.txt" Content-Type: text/plain

------WebKitFormBoundaryW40eoeeGdUtIafwW-- 上述回复包含了多个Part,每个Part都包含头部分。 Part 头信息中必须包含一个 Content-Disposition 头,其他的头信息则为可选项(如Content-Type等) Content-Disposition 包含了 type 和 一个名字为 name 的 parameter,type 是 form-data,name 参数的值则为表单控件(即 field);若是文件,那么还有一个 filename 参数(值=文件名) eg: Content-Disposition: form-data; name="txt3"; filename="old.txt" 对于可选的 Content-Type,默认=text/plain

关于 Boundary 分隔符 每个部分使用 --boundary 分割开来,最后一行使用 --boundary-- 结尾(如上,boundary="----WebKitFormBoundaryW40eoeeGdUtIafwW")

若文件内容是通过填充表单来获得,那么上传时,Content-Type 会被自动设置(识别)成相应的格式,如果没法识别,则设置成 "application/octet-stream";如果多个文件被填充成单个表单项,那么它们的请求格式则会是 multipart/mixed;如果 Part 的内容跟默认的 encoding 方式不同,那么会有一个 "content-transfer-encoding" 头信息来指定

GOLANG例子: var bufReader bytes.Buffer mpWriter := multipart.NewWriter(&bufReader) //写实例 fw, err := mpWriter.CreateFormFile("upload_file", fileName) if nil != err { return "", fmt.Errorf("CreateFormFile error: %+v\n", err) } defer mpWriter.Close()

`_, err = io.Copy(fw, bytes.NewReader(rspMsgContent))     //拷贝数据`
`if err != nil {`
	`return "", fmt.Errorf("copying from rspMsgContent %v\n", err)`
`}`
`mpWriter.WriteField("name", "rspmsg")`
`client = &http.Client{`
	`Timeout: 10 * time.Second,`
`}`
    `req, _ := http.NewRequest("POST", url, &bufReader)`
    `req.Header.Set("Content-Type", mpWriter.FormDataContentType())`
    `resp, err := client.Do(req)`
    `......`
⚠️ **GitHub.com Fallback** ⚠️