使用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)`
`......`