由http get与post想到的

httpgetpost

Jmingzi createdAt at 2年前

前言

我们需要清楚http是什么
http是web文档的传输协议,协议有很多种,还包括ip, ftp, dns, tcp等等,这些协议统称为tcp/ip协议族

tcp/ip协议族是分层管理的,即应用层 ,传输层 ,网络层 , 链路层

例如,当一个请求发出时,简单的来说:

  • 由应用层的http协议对请求进行处理(通过dns协议解析域名得到ip地址)。此时请求的数据为何种格式?
    • http协议将数据整理成报文格式,然后将报文以的形式传递给下层tcp
  • 由传输层的tcp(传输控制协议)等协议来规定如何进行传输。此时请求的数据为何种格式?
    • tcp将“报文流”分段,分装到ip分组中
  • 请求的数据格式被转化为数据包,网络层来规定数据包以何种路径进行传输
    • 在网络层,通过ip协议来得到传输路线。ip协议有2个重要条件ip地址mac地址
  • 链路层即用来处理连接网络的硬件部分,比如网卡等

我们此刻需要讨论的get与post,是属于应用层的http协议内容。与其它无关。

get与post的区别

首先,这个问题是有歧义的。

宽泛的说,它们都是基于tcp/ip协议族的,当然这句话说的没有任何意义,就像在放屁一样。

实际上,get与post只是http协议中定义的一种method,为约定俗成的针对某种情况下使用某种特定的方法,并没有严格意义上的不同。所以讲区别,只是说在使用上的一些区别与优劣。

就像html标签一样拥有特定的语义,在语义上的区别:

  • get更适合去获取由请求URI所指定资源的信息
  • post的具体功能由服务器来决定,我们一般用用实体信息扩展数据库

使用上的区别

  • get的请求参数是放在url上的,而post是放在request body即报文的请求主体中。
    但是http协议并没有规定必须这么做,这种做法只是一种规范,就跟es6中规定的const 与 let一样,你非得把一个不会变更的变量用let声明那也是没问题的。
  • 参数的长度限制,http协议也明确指出HTTP头和Body都没有长度的要求
    但由于规范,get的参数都是拼在url上的,url长度会被浏览器限制;另外,过长的url也会给服务器的解析造成负担。
    有说现代浏览器最大url长度为90kb的,在utf-8编码中,一个英文字母占据一个字节,一个中文占据3个字节;在ASCII码中,一个英文字母占据一个字节,一个中文占据2个字节;
  • get上的参数默认会以application/x-www-form-urlencoded格式,空格字符会被转化为+,非数字字母字符会被转化为%HH,即一个%和2个16进制的数字表示的ascii码
    当然也可以是二进制或其它格式,但是效率会很低

    The content type “application/x-www-form-urlencoded” is inefficient for sending large quantities of binary data or text containing non-ASCII characters

  • post的请求实体主体部分
  • 由于get是以url的形式请求响应的某种资源,它是可被缓存的;而post

以上有感于GET和POST有什么区别?及为什么网上的多数答案都是错的

http://man.chinaunix.net/develop/rfc/RFC1945.txt (方法定义(Method Definitions))

什么是request body

http报文分为请求报文和响应报文,结构基本一致。
请求报文格式如下

// 起始行 <method> <request-url> <version>
GET /images/test.jpg HTTP/1.1

// 首部 <headers>
Content-Type: application/x-www.form-urlencoded

// 实体 <entity-body>
name=ym&age=18

响应报文只有起始行不同

// <version> <status> <reason-phrase>
HTTP/1.1 200 OK

这里的request body便是请求实体主体entity-body

实体分为实体首部和实体主体,我们可以把“报文看作是箱子,实体看作是货物”

request body中的MIME类型

MIME类型即媒体类型,是一种标准,针对文件的。所以讲request body中的MIME类型,是指当Content-Typemultipart/form-data并添加了文件时才有的类型值。

MIME类型是标准化的名字,用以说明作为货物运载实体的基本媒体类型,客户端应用程序使用MIME类型来解释和处理其内容

MIME类型组成 主类型/子类型,常见的如下

text/html
application/vnd.ms-powerpoint
image/png

Content-Typemultipart/form-data时,实体的主体由多部分组成,每一部分的Content-Type默认为text/plain,举个例子

<FORM action="http://server.com/cgi/handle"
       enctype="multipart/form-data"
       method="post">
   <INPUT type="text" name="submit-name"> 
   <INPUT type="file" name="files">
 </FORM>

点击提交后的实体主体(文件多选)

   Content-Type: multipart/form-data; boundary=AaB03x

   --AaB03x
   Content-Disposition: form-data; name="submit-name"

   Larry
   --AaB03x
   Content-Disposition: form-data; name="files"
   Content-Type: multipart/mixed; boundary=BbC04y

   --BbC04y
   Content-Disposition: file; filename="file1.txt"
   Content-Type: text/plain

   ... contents of file1.txt ...
   --BbC04y
   Content-Disposition: file; filename="file2.gif"
   Content-Type: image/gif
   Content-Transfer-Encoding: binary

   ...contents of file2.gif...
   --BbC04y--
   --AaB03x--

input选择多个文件后,也就是批量上传,Content-Type就为multipart/mixed,相当于在Content-Type为multipart/form-data嵌入了Content-Type为multipart/mixed的部分。

If multiple files are to be returned as the result of a single form entry, they should be returned as “multipart/mixed” embedded within the “multipart/form-data”.

Content-Type还支持传递字符编码类型

Content-Type: application/x-www-form-urlencoded; charset=utf-8

规范的来讲不同的Content-Type应该使用不同的数据类型,例如

  • application/x-www-form-urlencoded 实体主体只能是一个字符串
  • multipart/form-data 实体的主体应该包含多部分,例如文件,二进制流或非acsll码的数据,contain files, non-ASCII data, and binary data

但是这不是绝对的,规范如下

The content type “application/x-www-form-urlencoded” is inefficient for sending large quantities of binary data or text containing non-ASCII characters. The content type “multipart/form-data” should be used for submitting forms that contain files, non-ASCII data, and binary data.

只是说效率会很低,是不建议这么做,并非不能。

https://www.w3.org/TR/REC-html40/interact/forms.html#form-data-set

什么是enctype

enctype是form表单的一个属性,用来指定http报文的编码方式,最终对应的也是上面说的Content-Type

http传递复杂数据类型的几种方式

对于简单数组 { key: [1, 2, 3] }来说

  • application/x-www-form-urlencoded,用qs的arrayFormat选项来说,有3种情况
    • brackets 形如key[]=1&key[]=2&key[]=3
    • repeat 形如 key=1&key=2&key=3
    • indices 形如 key[0]=1&key[1]=2&key[2]=3

具体使用哪种,需要与后端对接清楚。

它们的本质,都是拼接而来的字符串,我们知道,对于application/x-www-form-urlencoded,除了字母数字与+号,其余的都会转成ascll码,那对于嵌套的数据使用qs也是可以去做转化。但其实更适合用application/json,因为调试更清晰吧。

https://borninsummer.com/2015/10/27/about-using-json-in-http-body/

什么是 ASCII字符

除了ASCII,还有binary data,images, other files

什么是escaped

rest规范

rfc中文文档

git0

最后更新:2021年03月04日 14:54

鄂ICP备18011687号-1