• FormData 和 Content-Type: multipart/form-data


    一、FormData

    现代 Web 应用中频繁使用的一项功能就是表单数据序列化,XMLHttpRequest 2 级为此定义了 FormData 类型,FormData 为序列化表单以及创建与表单格式相同的数据(通过 JS 来模拟表单键值对)提供了便利。

       let xhr = new XMLHttpRequest()
    
        xhr.onreadystatechange = function (e) {
          if (xhr.readyState === 4) {
            if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
              console.log(xhr.responseText)
            } else {
              console.log('Opps~failed~!')
            }
          }
        }
        xhr.open('post', 'https://www.easy-mock.com/mock/59b95cf3e0dc663341a8fa20/example/upload', true)
    

    使用 post 发送表单键值对格式的请求时,依然可以使用查询字符串格式,只是要放在请求体中,即传入send()中,介绍以下几种方法:

    方法1:直接模仿表单提交的形式,缺点是需要手动设置请求头,还要自己序列化为查询字符串的形式传给 xhr 对象。

        xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
        const queryString = 'name=wangpeng&age=24&someNumberString=19'
        xhr.send(queryString)
    

    方法2:使用 FormData() 构造函数,浏览器会自动识别并添加请求头 "Content-Type: multipart/form-data",且参数依然像是表单提交时的那种键值对儿,此外 FormData() 构造函数 new 时可以直接传入 form 表单的 dom 节点。

        const params = new FormData()
        params.append('name', 'tom')
        params.append('age', 24)
        params.append('someNumberString', '18')
        xhr.send(params)
    

    方法3:使用 URLSearchParams() 构造函数传入查询字符串,返回的实例和 FormData 相似,同时浏览器也做出相同的行为。

        const params = new URLSearchParams()
        params.append('name', 'tom')
        params.append('age', 24)
        params.append('someNumberString', '18')
        xhr.send(params)
    

    另外,URLSearchParams() 构造函数 new 时可以直接传入查询字符串格式的参数,比如:

        const params = new URLSearchParams('name=tom&age=24&someNumberString=19')
    

    可见send()方法很灵活:

    xhr.send("foo=bar&lorem=ipsum"); 
    // xhr.send('string'); 
    // xhr.send(new Blob()); 
    // xhr.send(new Int8Array()); 
    // xhr.send({ form: 'data' }); 
    // xhr.send(document);
    

    二、multipart/form-data时的HTTP消息文本

    第一行是请求行,指明了方法、URI 和 HTTP 版本号;
    接着是消息头(简单起见,只有一个 Conten-Type);
    然后空出一行;
    接下来就是消息体,可以看到使用 multipart/form-data 时,消息体通过 boundary 来分隔多个字段,且每个字段都有自己的头部,提供了额外的信息。字段的值可能是普通的字符,也可能是二进制文件:

    POST http://www.example.com HTTP/1.1
    Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryyb1zYhTI38xpQxBK
    
    ------WebKitFormBoundaryyb1zYhTI38xpQxBK
    Content-Disposition: form-data; name="city_id"
    
    1
    ------WebKitFormBoundaryyb1zYhTI38xpQxBK
    Content-Disposition: form-data; name="company_id"
    
    2
    ------WebKitFormBoundaryyb1zYhTI38xpQxBK
    Content-Disposition: form-data; name="file"; filename="chrome.png"
    Content-Type: image/png
    
    PNG ... content of chrome.png ...
    ------WebKitFormBoundaryyb1zYhTI38xpQxBK--
    

    三、multipart/form-data定义源头

    multipart/form-data最初由 《RFC 1867: Form-based File Upload in HTML》文档定义。

    Since file-upload is a feature that will benefit many applications, this proposes an
    extension to HTML to allow information providers to express file upload requests uniformly, and a MIME compatible representation for file upload responses.

    文档简介中说明文件上传作为一种常见的需求,在目前(1995年)的html中的form表单格式中还不支持,因此发明了一种兼容此需求的MIME type。

    The encoding type application/x-www-form-urlencoded is inefficient for sending large quantities of binary data or text containing non-ASCII characters. Thus, a new media type,multipart/form-data, is proposed as a way of efficiently sending the
    values associated with a filled-out form from client to server.

    文档中也写了为什么要新增一个类型,而不使用旧有的application/x-www-form-urlencoded:因为旧有类型不适合用于传输大型二进制数据或者包含非ASCII字符的数据。平常我们使用这个类型都是把表单数据使用url编码后传送给后端,二进制文件当然没办法一起编码进去了。所以multipart/form-data就诞生了,专门用于有效的传输文件。


    参考:
    1. 豆瓣:JavaScript高级程序设计(第3版)
    2. MDN: FormData
    3. MDN: XMLHttpRequest.send()
    4. 为什么上传文件要使用multipart/form-data
    5. 谈谈form-data请求格式

  • 相关阅读:
    2018/12/06 L1-031 到底是不是太胖了 Java
    2018/12/06 L1-030 一帮一 Java
    2018/12/06 L1-029 是不是太胖了 Java
    .NET Framework 类库命名空间
    .NET获取根目录
    ddd领域驱动设计
    垃圾回收
    rest api
    数据库ACID
    事务隔离级别
  • 原文地址:https://www.cnblogs.com/nicholaswang/p/11459860.html
Copyright © 2020-2023  润新知