multipart/form-data

Posted qiqi715

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了multipart/form-data相关的知识,希望对你有一定的参考价值。

目录

一.什么是multipart/form-data

首先我们需要明白在html中的enctype属性.
enctype:规定了form表单在发送到服务器时候编码方式。有如下的三个值。
application/x-www-form-urlencoded。默认的编码方式。但是在用文本的传输和MP3等大型文件的时候,使用这种编码就显得 效率低下。
multipart/form-data 。 指定传输数据为二进制类型,比如图片、mp3、文件。
text/plain。纯文体的传输。空格转换为 “+” 加号,但不对特殊字符编码。

二.明确在enctype参数为application/x-www-form-urlencoded的时候post和get请求参数和请求体是什么形式的

2.1 get请求

请求头:

GET/www.xxx.com?name=%22hello+world%22&**file=temp.png**&submit=submit HTTP/1.1

因为get请求没有请求体,所有他的所有参数都是在url的后边添加。type=file的表单项只能获取到文件的名字,并不能获取文件的内容。

2.2 post请求

请求头:

POST /www.baidu.com HTTP/1.1

请求体:

name=%22hello+world%22&file=temp.png&submit=submit

(1)我们可以发现不管是post请求和get请求,他们的参数存在的形式都是不变的,通过key=value的形式存在。
(2)表单项type=filed只能获取获取文件的名字不能获取文件的内容。

三. multipart/form-data

...
Content-Type: multipart/form-data; boundary=${boundary}

--${boundary}
...
...

--${boundary}--

请求内容格式为Content-Type: multipart/form-data,用来指定请求内容的数据编码格式。

3.1 boundary字符串

该格式会生成一个boundary字符串来分割请求头与请求体的,具体的是以一个boundary=${boundary}来进行分割。

1、上面boundary=${boundary}之后就是请求体内容了,
2、请求体内容各字段之间以--${boundary}来进行分割,
3、以--${boundary}--来结束请求体内容。

3.2 get请求 无效

请求头:

GET/www.xxx.com?name=%22hello+world%22&file=temp.png&submit=submit HTTP/1.1

get请求和multipart/form-data结合无效,因为文件上传需要请求体

3.3 post请求:

请求头:

POST /www.xxx.com HTTP/1.1

请求体:

------WebKitFormBoundaryIZDrYHwuf2VJdpHw
Content-Disposition: form-data; name="name"

"hello world"
------WebKitFormBoundaryIZDrYHwuf2VJdpHw
Content-Disposition: form-data; name="file"; filename="temp.png"
Content-Type: image/png

.PNG
.
...
IHDR...
..........Y../..,+|.$aIk.v...G?...P.P,,...m..e.2....v.7.    pHYs...%...%.IR$....|IDAT(.cTT....................:.?.......}.(.Pd`A..V...L...?..#.....4.o..LS.....W.d.?...A8..LS...(.u.......D.b......b.....o&..;..<.1......IEND.B`.
------WebKitFormBoundaryIZDrYHwuf2VJdpHw
Content-Disposition: form-data; name="submit"

submit
------WebKitFormBoundaryIZDrYHwuf2VJdpHw--

3.4 多部件请求体

通过观察发现这个的请求体就发生了变化。这种请求体被称之为多部件请求体
什么是多部件请求体:就是把每一个表单项分割为一个部件。
因为表单项分为普通表单项文件表单项,所以说部件也有区别。

3.4.1 普通表单项:

  • 一个请求头:Content-Disposition: form-data; name=”name”
  • 一个请求体:里面就是我们表单的值”hello world”

3.4.2 文件表单项:

  • 两个请求头:
    • Content-Disposition: form-data; name="file";
    • filename="temp.png"
  • 一个请求体:
.PNG
.
...
IHDR...
..........Y../..,+|.$aIk.v...G?...P.P,,...m..e.2....v.7.    pHYs...%...%.IR$....|IDAT(.cTT....................:.?.......}.(.Pd`A..V...L...?..#.....4.o..LS.....W.d.?...A8..LS...(.u.......D.b......b.....o&..;..<.1......IEND.B`.
------WebKitFormBoundaryIZDrYHwuf2VJdpHw
Content-Disposition: form-data; name="submit"

submit
------WebKitFormBoundaryIZDrYHwuf2VJdpHw--

3.5 FormData对象

XMLHttpRequest Level 2添加了一个新的接口FormData。利用FormData对象,我们可以通过javascript用一些键值对来模拟一系列表单控件,我们还可以使用XMLHttpRequest的send()方法来异步的提交这个"表单"。

var formData = new FormData();
formData.append("username", "Groucho");
formData.append("accountnum", 123456);
fetch(‘/users‘, {
  method: ‘POST‘,
  body: formData
})

上面创建了一个FormData对象,通过fetch进行ajax请求时,会自动为其将其转为form-data格式,无需手动添加格式。

3.6 对象转FormData对象

对于FormDat对象,像上面那种形式可以直接添加参数比较方便,但是对于对象或者嵌套对象:

 let userObj = {userName: ’xxx‘, age: ‘21‘};
 formData.append(‘user‘, userObj);

上面形式添加formData参数user,并不会获取到其真正的内容,而是返回userObj的Object.prototype.toString.call(userObj)的值作为user字段的值。

------WebKitFormBoundaryyb1zYhTI38xpQxBK
Content-Disposition: form-data; name="user"

[object Object]

遗憾的是,FormData对象没有像JSON.stringify那样的方法能批量将对象形式转换为对应的形式,formData而言是将对象的key转换为正确formData请求参数字段名,例如如下对象:

var obj = {
    a: ‘2‘,
    b: {c: ‘test‘},
    c: [
        {id: 1, name: ‘xx‘},
        {id:2 ,name: ‘yy‘, info: {d: 4} }
    ]
}

这样转换为FormData对象时,其对应的key应该是下面这样的:

a: 2
b[c]: test
c[][id]: 1
c[][name]: xx
c[][id]: 2
c[][name]: yy
c[][info][d]:4

这样,就需要我们自己手动来实现一个转换数据函数,具体代码如下:

function objectToFormData (obj, form, namespace) {
  const fd = form || new FormData();
  let formKey;

  for(var property in obj) {
      if(obj.hasOwnProperty(property)) {
        let key = Array.isArray(obj) ? ‘[]‘ : `[${property}]`;
        if(namespace) {
          formKey = namespace + key;
        } else {
          formKey = property;
        }

        // if the property is an object, but not a File, use recursivity.
        if(typeof obj[property] === ‘object‘ && !(obj[property] instanceof File)) {
          objectToFormData(obj[property], fd, formKey);
        } else {

          // if it‘s a string or a File object
          fd.append(formKey, obj[property]);
        }

      }
    }

  return fd;

}

这样,就可以将对象转化为对应的formData的格式了。










以上是关于multipart/form-data的主要内容,如果未能解决你的问题,请参考以下文章

如何从 WCF 服务返回 multipart/form-data 作为响应

Jersey API 中的 multipart/form-data 出现 CORS 错误

Httpclient multipart/form-data同时发布图片和json

webapi不使用MultipartFormDataStreamProvider上传multipart form-data数据的方法

php:使用“enctype =“multipart/form-data””的文件加载不起作用

使用 multipart/form-data 将图像从移动应用程序上传到 API