POST提交数据的几种方式

344 篇文章 10 订阅
<span hidden="" itemprop="author" itemscope="" itemtype="http://schema.org/Person">
  <meta itemprop="name" content="LiYang">
  <meta itemprop="description" content="">
  <meta itemprop="image" content="/images/avatar.jpg">
</span>

<span hidden="" itemprop="publisher" itemscope="" itemtype="http://schema.org/Organization">
  <meta itemprop="name" content="Leon's Blog">
</span>


  <header class="post-header">

    
    
      <h1 class="post-title" itemprop="name headline">
        
        
          
            POST提交数据的几种方式
          
        
      </h1>
    

    <div class="post-meta">
      <span class="post-time">
        
          <span class="post-meta-item-icon">
            <i class="fa fa-calendar-o"></i>
          </span>
          
            <span class="post-meta-item-text">发表于</span>
          
          <time title="创建于" itemprop="dateCreated datePublished" datetime="2019-03-30T15:57:49+08:00">
            2019-03-30
          </time>
        

        

        
      </span>

      

      
        
      

      
      

      
        <span class="post-meta-divider">|</span>
        <span class="page-pv">本文总阅读量
        <span class="busuanzi-value" id="busuanzi_value_page_pv">516</span>次
        </span>
      

      

      

    </div>
  </header>



<div class="post-body" itemprop="articleBody">

  
  

  
    <p>提到HTTP使用<code>POST</code>请求提交数据的方式,第一反应就是以对象形式提交,如果是文件,则换成<code>formData</code>形式提交。除此之外好像还有个一长串的<code>x-www-form-urlencoded</code>,可这全是碎片化的知识点,毫无章法。最近做项目时用到了<code>axios</code>,详细的翻看了一下文档,有个地方引起了我的兴趣:<code>By default, axios serializes JavaScript objects to JSON. To send data in the application/x-www-form-urlencoded format instead, you can use one of the following options</code>。等等,这里说<code>axios</code>默认使用序列化的<code>JSON</code>发送数据,但如果你要使用<code>application/x-www-form-urlencoded</code>格式的话,可以使用<code>qs</code>库或者<code>new URLSearchParams()</code>。赶紧网上查阅资料,才发现自己遇到了知识盲点,现系统的总结一下这个小知识点。</p>

概述

常用的HTTP请求方法有GETPOSTPUTDELETEHEADOPTIONS等。客户端发送一个HTTP请求到服务器,这个请求消息包括:请求行、请求头部、空行和请求数据:

1
2
3
4
<method> <request-url> <version>
<headers>

<entity-body>

我们使用POST发送的数据必须放在消息主体(entity-body)中,但是HTTP协议并没有规定使用什么样的编码方式来传送数据。这个编码方式前端可以自己来决定,但是数据发出去,还要服务端能解析成功才有意义。服务端自有不同的方法来解析不同编码格式的数据,而且服务端可以根据请求头(headers)内的Content-Type字段去获知编码方式,然后去解析数据。

几种常见的Content-Type类型

application/x-www-form-urlencoded

application/x-www-form-urlencoded是一种比较常见的编码方式。我们在使用浏览器原生的form表单提交数据时,如果没有指定enctype属性,则默认会以该方式提交数据。

1
2
3
4
5
<form action="http://www.baidu.com" method="post">
<input type="text" name="name">
<input type="text" name="age">
<button type="submit">提交</button>
</form>

在浏览里可以看到:

首先,我们看到请求头Request Headers内的Content-Type字段被设置为了application/x-www-form-urlencoded;其次,提交的数据按照key1=value1&key2=value2的方式进行了编码,服务端语言对这种编码方式有很好的支持。

multipart/form-data

当我们在上传图片或者文件的时候,会用到这种编码方式。如果使用原生form表单,则需要将enctype设置为multipart/form-data进行提交。如果使用ajax库,则需要以formData的形式提交数据:

1
2
3
4
5
6
7
let _formData = new FormData();
_formData.append('file', file);
_formData.append('suffix', suffix);
_formData.append('perpetual', true);
_formData.append('applicationId', applicationId);
_formData.append('partyId', partyId);
api.saveHeadImg(_formData).then(console.log(res));

在浏览器中:

首先,请求头内Content-Type除了有multipart/form-data;外,额外生成了一个boundary字段,这个字段用来分割请求数据内的不同字段。在请求体内,数据字段每部分都是以--boundary开头,紧接着是内容描述信息,包括字段名称,字段值等。请求体最后以--boundary—标识结束。

application/json

application/json作为响应头或者请求头都非常常见。这种编码方式会告诉服务端提交的数据类型是序列化后的JSON字符串,前端在调接口提交数据时,直接以对象形式传递数据即可。

1
2
3
4
5
let params = {
loanApplyNo: 'XTFQ201903270010',
returnUrl: window.location.origin + '/loan/result',
};
api.saveData(params).then(console.log(res));

在浏览器端:

axios这个库默认就是使用序列化的JSON形式POST数据。但如果服务器端比较蛋疼的规定只接收application/x-www-form-urlencoded格式,则可以使用qs库或者URLSearchParams API来做转换处理:

1
2
3
4
5
6
7
8
const params = new URLSearchParams();
params.append('param1', 'value1');
params.append('param2', 'value2');
axios.post('/foo', params);

//或者
import qs from 'qs';
axios.post('/foo', qs.stringify({ 'bar': 123 }));

写到这里,想到Angular4+同样提供了 HttpParams 类来将普通对象转换为application/x-www-form-urlencoded。当时写Angular的时候还没意识到这一点,真是糊涂。

以上就是平时用到最多的三种POST数据类型,当然还有其他的编码格式,但是我暂时还未用到或者见到过。日后使用到其他格式类型,可以继续补充。

</div>

<div>
  
    

  
</div>

<div>
  
    

  
</div>

<div>
  
    

  
</div>

<footer class="post-footer">
  
    <div class="post-tags">
      
        <a href="/tags/随写/" rel="tag"># 随写</a>
      
        <a href="/tags/HTTP/" rel="tag"># HTTP</a>
      
    </div>
  

  
    
  

  
    <div class="post-nav">
      <div class="post-nav-next post-nav-item">
        
          <a href="/2019/03/16/RxJS学习总结-Subject/" rel="next" title="RxJS学习总结-Subject">
            <i class="fa fa-chevron-left"></i> RxJS学习总结-Subject
          </a>
        
      </div>

      <span class="post-nav-divider"></span>

      <div class="post-nav-prev post-nav-item">
        
          <a href="/2019/04/13/React源码学习-Fiber遍历/" rel="prev" title="React源码学习-Fiber遍历">
            React源码学习-Fiber遍历 <i class="fa fa-chevron-right"></i>
          </a>
        
      </div>
    </div>
  

  
  
</footer>

本文所讲的 POST 请求是 HTTP/1.1 协议中规定的众多 HTTP 请求方法的其中最常用的一个。一般使用 POST 请求方法向服务器发送数据(主要是一些创建更新操作),本文讨论的是 POST 请求方法常用的四种数据提交格式。

由于 HTTP/1.1 协议中并没有对请求使用什么编码方式进行规定,所以理论上开发者完全可以自己决定请求的 Body 体使用什么格式,当然实际上大家都还是用通用的那么几种编码方式来提交数据(生态很关键)。

注:以下排名不分先后。。。

application/x-www-form-urlencoded

对于浏览器原生的 form 表单,enctype 的值不指定的话,默认就是这个家伙。实际上大部分情况都使用它即可,编码方式足够简单高效,各方面支持也都很完备,如各大浏览器调试工具、各大抓包软件等。

key1=val1&key2=val2" title="" data-original-title=“复制”>

POST http://www.example.com HTTP/1.1
Content-Type: application/x-www-form-urlencoded;charset=utf-8

key1=val1&key2=val2

基本的请求类似上面这样,数据的编码方式采用 key1=val1&key2=val2 的形式,对其中的键值对都需要使用 URL Encode 编码一下。其实就是和 GET 请求的数据提交格式是一样的,只不过位置从 Request URL 上换到了 Request Body 里。

这种格式结构简单,但对于数据层级较深的情况,比如一些有复杂层级关系的接口数据,这种方式就显得有点力不从心了。另一方面,对于需要上传二进制数据(比如图像、音频等文件),这种方式就不那么高效了,而且对于非 ASCII 码的数据就丢失了,所以传文件的情况就不能使用这种方式。

适用场景:数据量不大、数据层级不深的情况下强烈建议这种数据提交格式。

multipart/form-data

当你需要提交文件、非 ASCII 码的数据或者是二进制流数据,则使用这种提交方式。类似下面这个请求示例:

------WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition: form-data; name="text"

demo
------WebKitFormBoundaryPAlLG7hJKNYc4ft3
Content-Disposition: form-data; name="file"; filename="demo.png"
Content-Type: image/png

------WebKitFormBoundaryPAlLG7hJKNYc4ft3–" title="" data-original-title=“复制”>

POST http://www.example.com HTTP/1.1
Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryPAlLG7hJKNYc4ft3

------WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition: form-data; name=“text”

demo
------WebKitFormBoundaryPAlLG7hJKNYc4ft3
Content-Disposition: form-data; name=“file”; filename=“demo.png”
Content-Type: image/png

------WebKitFormBoundaryPAlLG7hJKNYc4ft3–

第二行指定编码方式 Content-Type 为 multipart/form-data,紧接着生成一个分界线 boundary 即 ----WebKitFormBoundaryPAlLG7hJKNYc4ft3,又臭又长的目的是为了避免和 Body 正文内容有冲突,它的作用是用来分隔不同的字段。

Body 体分为多个结构类似的部分,每一部分以 --boundary 开头,因为本次请求生成的 boundary 为 ----WebKitFormBoundaryPAlLG7hJKNYc4ft3,所以最终是 ------WebKitFormBoundaryPAlLG7hJKNYc4ft3。接着是描述内容的元信息,包括字段名称,如果是文件则还有文件名称和文件类型。接着留一空行,然后才是字段值。什么时候结束呢,以 --boundary-- 标志结束。

这种方式本就是专为上传文件的场景设计的,虽然你也可以使用这种方式传递普通数据,但无疑会增加不少数据包的大小(这么多 boundary 还是有不少空间占用的)。

适用场景:文件上传。

application/json

很明显在 JSON 格式火之前,肯定没有它的,前面说到使用什么提交数据方式是没有硬性规定的,所以在 JSON 格式火了以后,尤其以其优秀的数据结构表达能力,逐渐流行开来,现在我们对它完全不会陌生。

{“name”:“xfly”,“age”: 24, “hobby”:[“x”,“xx”,“xxx”]}" title="" data-original-title=“复制”>

POST http://www.example.com HTTP/1.1
Content-Type: application/json;charset=utf-8

{“name”:“xfly”,“age”: 24, “hobby”:[“x”,“xx”,“xxx”]}

适用场景:数据结构较复杂,层级较深的情况。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值