如果是我标题党,这篇文章的标题应该是“要了解GET和POST,这篇文章就够了”,或者“如果面试官问你GET和POST,把这篇文章甩给它!”。
工作中经常面试和技术交流中,笔者觉得很多开发者甚至比较资深的,好像对HTTP协议的理解都没有达到适当的水准。所以本文觉得有必要从一个常见的话题:“HTTP GET和POST方法的联系和区别”出发,以HTTP协议作为基础来进行讨论和研究。而且笔者觉得这个问题对于Web应用的开发非常重要,因为它涉及到所有Web应用程序的最基本、最核心的东西。
HTTP协议和Web技术的发展
我们现在这个技术宇宙所说的互联网应用或者网络应用,基本上都是选择HTTP(应用层)/TCP(网络层)协议作为其主要通讯和应用协议。理论上可以有其他的技术方案,但在现实世界中没有出现。原因很简单,就是它天生就是免费、自由、开放、可扩展和进化的,天生适合互联网这种开放性的应用场景。这里不得不佩服这套协议和架构的开创者,因为人类社会基本上以前没有类似的经验和知识可以借鉴。它的设计目的并不只是为了解决某个特定的技术问题,而是建构一个可以包容不同层次和利益关系的生态系统。最终,成就了现在互联网这个生机勃勃、丰富多彩的世界。
我们还需要理解,“罗马不是一天建成的”,Web技术也是这样。它有一个逐渐发展,逐渐完善,并且在发展中完善的过程。互联网之所以能够如此发展,很大程度上也是由于这个原因。坐言起行,先能用再好用,要考虑扩展性但不也能考虑的太过长远,在发展中解决问题,这些都是这个行业从业者秉持的技术观和发展理念。
最早的Web技术是基于“页面”的,完全的使用静态的页面文件,使用URL地址进行标识和连接,在服务端只需要处理文件,这样最简单方便;然后随着技术和需求的发展,页面不再是静态的了,而是可以基于请求的参数,可以由服务器端部署的程序,按需生成“动态”的页面。这也是主流的传统Web应用的实现方式。
这里,虽然做到了动态,但本质上,还是基于页面的技术,因为程序需要生成一个完整的页面。这样做的缺陷显而易见,因为在大多数的应用场景中,页面的框架和布局就是那么几类,不同的页面差异的主要是页面的内容,很多的差异,就只有一些文本和数字,但为了这么小差异的内容,也需要服务器和客户端生成、传输和处理整个页面,显得相当的笨拙和低效(但也有一个优势就是--简单)。
因此,很自然的,就进一步产生了AJAX技术。AJAX技术允许在页面加载完成之后,可以根据场景和需求,在页面的上下文中,再次发起HTTP请求,获取“片段化”的信息而非整个页面,称之为“异步Javascript和XML”。这部分内容我们会在后面详细探讨。这里我们只需要了解,使用AJAX,Web应用就获得了极大的灵活性和效率,真正的完成了从“页面”到“应用”的质的转变,也是当前主流的Web应用技术模式。
可能有读者会有疑问,AJAX技术这么好,为什么没有一开始就这样设计呢? 这基本上是一个哲学问题。笔者理解,人类的需求、应用和认知发展其实也是有一个过程的,在开始之前没有人拥有上帝视角,很多需求的挖掘和实现的创造是在应用的过程中才出现的,这一阶段基本上不可能跳过。是为“知行合一”也。其实,从过去的历史和经验来看,和其他的技术进步(如汽车、飞机等)相比,互联网作为一个可以自我促进和进化的产业,其发展速度已经是非常惊人的了。
好了,回到主题。我们发现,前面无论Web应用如何发展变化,其核心和基础,始终是基本的HTTP协议。HTTP(Hyper Text Transport Protocal)就是超文本传输协议。我们先从字面意思上理解一下。超文本,它的基础还是文本,但可以处理除文本之外的信息;协议是一种标准和规范,技术实施者应该尽力实践和遵循此规范,以达到更好的实现效果、效率和兼容稳定;这个协议,是用于规范和控制超文本信息传输过程的目的而设计的,所以它是一个应用层的协议。作为协议,它必须具有逻辑可靠性、广泛的业务适应性和可扩展性。为了达到这个目的,它基于所有应用和业务模式进行了高度抽象,并制定了一整套相关的规范和内容。
比如,它将所有的业务操作和流程,都分解抽象成为单一的请求/响应的过程模型,并匹配了客户端/服务器的信息系统应用和网络架构。客户端请求,然后服务端响应,有请求才有响应,没有请求就没有响应,而且请求响应是无状态的,就是这次请求响应和下一次完全没有关联,清晰简单而明确(当然,这也造成了很多安全的问题,需要在后面的版本和业务实现中进行弥补)。其次,它设计和规范了URL(Universal Resource Location,统一资源定位)的定义和使用,并将所有的业务操作都抽象称为对资源(URL)的操作;然后它将所有的业务操作行为,在资源层面上都抽象称为CUDG(Create创建、Update更新、Delete删除、Get获取(查询是广义的获取)四个类型),并配套了相关的HTTP方法语义和操作规范。它还定义了一套业务过程和资源状态的编码和标识,几乎覆盖了几乎所有网络应用的操作状态和异常情况。
从这些意义上而言,HTTP,其实就是Web应用世界的宪法。从某种意义上而言,我们现在在各种操作系统、应用平台和环境中,使用不同的开放语言和工具,操作的各种框架和技术,针对各种各样客户端、服务器、浏览器和终端设备的形态,进行的各种各样的Web应用开发,所做的其实都是一件事,就是对HTTP协议的应用和操作。笔者觉得,这就是Web应用开发的实质。
HTTP协议的内容是如此广博,我们不可能在一篇文章中涵盖。所以笔者想要先从HTTP的基础入手,就是初步的理解HTTP请求和响应的处理过程。也许在下次的技术面试过程中能够言之有物。
HTTP请求和响应过程分析
这里就简单分析一下,HTTP请求和响应处理的原理。在一般情况下,比如在网页中我们点击一个链接(或者在浏览器地址栏中输入并确认一个URL地址),或者提交一个表单,浏览器就按照一些通用的规则和设定,发起一个HTTP请求。它们在HTTP协议文本内容的层面,可能是这样的:
// GET请求
GET / HTTP/1.1
Host: developer.mozilla.org
Accept-Language: fr
// POST请求
POST /contact.php HTTP/1.1
Host: developer.mozilla.org
Content-Length: 64
Content-Type: application/x-www-form-urlencoded
name=Joe%20User&request=Send%20me%20one%20of%20your%20catalogue
当然最终的请求信息肯定是一些二进制代码,这里显示为文本来方便人类的理解和操作,这也是HTTP作为应用层协议的体现。我们如果不使用浏览器,而是使用telnet程序来连接服务器,就可以使用命令行程序来发送这些指令,也可以达到类似的效果(图为Wireshark截获的HTTP请求信息代码流)。
在这个请求真正发起之前,我们其实忽略了浏览器的很多前期准备的工作,包括使用DNS来解析域名,或者服务器的公网IP地址,然后和服务器建立TCP连接等等,因为这不是本文重点关注的内容。我们的关注从建立连接后的请求过程开始。这个连接建立完成之后,客户端就可以向服务端发送类似上面的信息,称之为请求。请求内容的组成和方式,是由HTTP协议规范的。通常第一行就是一个指令行,以一个动词开始告知服务器要进行何种操作或者后续处理(如GET和POST,其具体意义后面讨论); 在同一行,还有请求资源的路径(/ 或者/contact.php),就是希望对什么东西进行操作;然后是协议和版本号。
随后会有一些内容我们可以看到是冒号分隔的内容行,它们是一些控制信息,称为头信息(Header),它是以键值对的方式组织和发送的。这些键名称和内容,也是HTTP规范规定的,但开发者也可以自己定义和扩展头信息,来满足业务的需求,比如可以设置一个头信息来保存请求时使用的令牌。
如果是GET请求,到头信息全部内容就完成了;但如果是POST请求,随后就是具体的请求内容。在头信息中,可以预先定义请求内容的长度和格式,方便服务器端进行处理。如果我们使用表单提交信息时,按照规范浏览器会使用x-www-form-urlcencoded格式,将内容编码和组织后放在请求体中,就像我们在示例中看到的那样。其实,这个内容也是可以高度自定义的,逻辑上我们可以发送任何内容,只需要在服务器端有对应的解析机制,也可以达到传输信息的目的。
客户端发送请求后,服务端会接收到请求内容。它可以根据请求的方式和内容,决定如何进行处理。处理完成后,服务端也应当按照HTTP的规范,向客户端发送处理的结果和状态等信息,称为响应。
下面是一个典型的HTTP响应内容。可以看到,响应的第一行是协议版本和响应状态(消息)。然后也是一些头信息的内容;最后就是实际响应的内容,这里是一个HTML文本,浏览器可以将它展示在网页中。
HTTP/1.1 200 OK
Content-Type: text/html;
Content-Length: 55743
Connection: keep-alive
Cache-Control: s-maxage=300, public, max-age=0
Content-Language: en-US
Date: Thu, 06 Dec 2018 17:37:18 GMT
ETag: "2e77ad1dc6ab0b53a2996dfd4653c1c3"
Server: meinheld/0.6.1
Strict-Transport-Security: max-age=63072000
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
Vary: Accept-Encoding,Cookie
Age: 7
A simple webpage
Simple HTML webpage
Hello, world!
我们通常在应用层面,就是简单的点击链接或者提交表单,然后服务器会响应一个页面给我们显示在浏览器中。但经过上面的分析,我们就可以看到,其实在这个过程中,浏览器按照协议的规范,其实做了很多附加的工作。作为用户我们可以不关心这些在幕后的内容,但作为开发者,我们需要更深入的了解和理解,才能开发出更好的应用程序。
GET vs POST
好了,在了解了HTTP协议和基础的请求响应机制后,终于来到了本文的主题题。我们可以基于对HTTP协议的理解,总结一下这GET和POST这两个HTTP方法的联系和区别。
- 语义
前面我们提到,GET和POST其实是两个指令,可以指示服务器如何进行后续的处理。在HTTP协议的设计中,Get和Post都是有其明确的语义的。这里面有两个主要的内容,一是这两个方法都是客户端相对于服务器的行为和操作而言的,二是操作的目标和对象都是服务器保存的资源,其实就是某些信息或者数据对象。
所以,在语义上,Get(获取)常用于客户端从服务器获取或者查询资源;而Post(粘贴)通常用于在服务器上创建新的资源。这个资源的地址,都必须明确提供,是不能忽略的。
HTTP还有一个方法Put,在协议设计的语义上是用于更新资源内容的,但实际应用的场合一般觉得和Post的功能重复了,所以用的很少,只使用Post来创建和更新数据,实际上将两种操作简化合并了。
- 内容编码
GET请求方法的内容,其实就是请求时使用的URL地址,按照HTTP的规范,这个地址只能使用ASCII字符。这里可能读者就会有疑问说,我们在使用浏览器点击一些链接的时候,里面是有中文的啊?确实是这样,但这其实是浏览器帮你进行了处理和转换,它在提交时,将中文等内容转换成UTF8的ASCII字符编码的表示方式。
关于这一点,我们可以做一个简单的实验。比如我们使用chrome浏览器,访问bing.com来进行一个简单的搜索,我们在地址栏里面可以看到确实搜索的关键字是中文,但如果我们打开开发工具,就可以看到真正的请求地址是编码后的地址了(如图)。
如果仔细观察,就可以发现,原来的搜索关键字“中文”,在这里被编码成了: %E4%B8%AD%E6%96%87。这其实就是它的UTF8编码内容,是字节数组(hex编码) [E4,B8,AD,E6,96,87],然后这里百分号的意思就是这部分内容是字节内容。这是URL地址的编码规范确定的。
对于POST请求而言,其URL部分的内容和GET是一样的。而其请求体的内容,其实是没有什么限制的,取决于其实现的方式。如果使用古早的表单提交方式,那么默认的内容形式应该是:application/x-www-form-urlencoded; 而参数内容的编码方式也是和URL是一样的,使用k1=v1&k2=v2... 这种形式。
- 安全
对于很多初学者的认知而言,他们觉得Post比Get要安全,理由是Get请求,所有的参数都在URL里面,并且在浏览器的地址栏里面能够看到;而Post请求,内容数据都在请求体中,如果使用浏览器,就会在表单或者AJAX请求对象之中,是比较安全的。这个其实是对信息安全的认知是不足的。
先说结论,GET方法和POST方法,在真正的网络信息安全性方面,是没有差异的。
在网络应用环境中,信息和数据的安全主要并不体现在“人”的感知和认知之上。而主要是数据在网络传输过程中的可用性、机密性、完整性和不可抵赖性。这些在技术上都是通过密码学的算法和对数据的操作处理来保证的。
实际上,我们可以从攻击者的角度,来了解一下发起并实现HTTP网络攻击的过程。排除掉社会工程的部分,他们可能主要通常采用分析用户操作,网络流量嗅探或者劫持的方式。比如植入木马程序监控用户的操作,或者侦听在网络传输链路中的信息,如TCP/IP数据包,来获取其中泄露的信息。他们一般都是隐藏在网络的角落,从远程偷偷的操作,而不是站在用户的后面,偷偷查看其在屏幕上的操作和内容。
所以,在理解了HTTP协议的工作原理和过程之后,我们就知道GET和POST方法,在TCP协议的层面,在网络上传输的方式和内容没有本质的区别。而如果使用HTTPS协议,则所有实际的HTTP流量都会被加密,安全性方面也是一样的。
- 参数
Get方法的参数主要体现在URL地址中。我们经常看到的形式就是?k1=v2&k2=v2...,一般称为queryString。但其实这也是一个建议规则。开发者可以在URL法定字符集内使用任意编码规则的URL字符串,只不过需要在服务端有相应处理的机制。如笔者喜欢使用JSON的base64URL编码方式来表示请求参数。
Post方法的参数,当然主要是在请求内容体当中了。一般的形式也有好几种。比如原来经常使用的表单方式,AJAX请求经常使用的JSON方式。其实HTTP规范并没有限制这部分的内容,只有一些约定常用的方式。
当POST使用表单方式的时候。 默认情况下,请求的内容的格式是application/x-www-form-urlencoded。而且它的参数组织形式也使用queryString。
如果是AJAX请求,则开发者有机会自己来定义请求的内容。为了处理方便一般使用JSON的序列化方式,就是直接将JSON对象的字符串形式作为请求体。甚至自己定义参数的组织和表达形式,如csv等等。
- 容量
GET方法,能够承载数据的容量,显然是体现在那个URL地址字符串的长度之上的。POST方法的数据和信息都在请求体中。 其实从HTTP协议规范的角度,两种都是没有限制的,但在工程和应用的角度,在浏览器和服务端都会进行一些限制。
所以,在客户端和浏览器中的限制首先取决于这一端的技术实现。每个浏览器甚至不同的版本可能都不一样。古早的浏览器有一个约定俗成的URL长度的限制是1024比特,但由于技术和业务的发展,这个限制在现代的应用场景下显得有点紧张,所以现在的Chrome浏览器对于URL的限制是8182个字符,Firefox更高一点是65535字符,最少的是IE,2083字节,我们在开发时以这个作为标准基本上就可以了。这个URL长度在服务器端的限制其实也取决于其技术实现,但一般情况下远都超过客户端,所以通常情况下大家都不太在意。
POST方法的情况稍微复杂一点,因为它可能由URL地址和请求体构成,要考虑两种的情况。URL的情况已经在前面讨论过。关于请求体,由于客户端需要考虑传输文件的需求,HTTP协议设计了mulitPart多数据体的请求机制,基本上可以不考虑这个限制。反而是在服务端,出于处理效率和需要为大规模客户端提供服务的稳定性的考虑,需要做一些相关的限制。当然这个也取决于服务端的技术实现。
- 操作过程
GET基本上是一个单一简单的请求过程。而基于HTTP协议的规范,POST方法基于浏览器的实现和场景,有可能会产生两次请求。特别是涉及到可能跨域请求的情况,浏览器可能先发起一个OPTION请求,如果响应正常,才真正的进行POST请求。但显然,这个操作是浏览器实现的一种安全机制,其实和POST方法本身的定义和规范是无关的。
- 缓存
这个也和客户端及服务端的实现有关。对于GET请求,为了提升性能,会假设数据在一定时间内或者条件下是稳定不变的,客户端和服务端都可能会使用缓存机制。而POST请求由于涉及到数据的修改,通常不会使用缓存机制。
有些开发者不太明了其中细微的差异,设计和实现HTTP API的时候,都简化为使用和处理POST方法,虽然可能从业务和应用的角度而言没有什么差别,但可能会对性能造成一些影响。
实际上,合理的使用缓存,是应用程序性能优化的一个非常重要的方面。应用程序开发和架构的水平,也能在这方面体现。
- 幂等性
GET主要用于获取数据,在条件不变,并且原始数据稳定的情况下,应该每次获取的数据都是一样的。所以通常认为GET是“幂等的”,也进一步被认为在这种情况下,是相对“安全”的,就是无论怎样操作,都不会造成服务器端的资源和数据被修改。但如果实现的不规范合理,就是GET方法也能够用来修改数据,就容易留下被攻击的漏洞。
- Cookie
可能有一些开发者觉得,GET和POST方法对于Cookie的使用可能会有所不同,但理解的cookie的工作原理和本质后,就知道它其实是附加在请求或者响应头上的指令信息,大部分情况是由浏览器和服务端程序自动处理的,和请求的方法方式其实是没有关系的。
这里需要强调一下,cookie是一种自动处理机制,即如果服务端设置了cookie,那么在随后的客户端请求中,浏览器会自动的在请求头上加入cookie信息。这很容易被滥用,因为并不是所有的请求都需要这个cookie(图片、css、js文件等),这样会造成很多无谓的网络传输,所以设置cookie甚至涉及规划应用程序的架构都需要合理。
- 小结
经过上面的讨论,我们应该已经能够了解到,GET和POST其实就是一个“行为声明”,用于客户端在请求时声明想要做什么。在HTTP协议的请求模型的层面上,其实没有什么差异。而在开发和应用上的差异,主要是浏览器在请求过程的具体实现和操作中,体现出来的。
下面我们来进一步探讨,在比较现代的HTTP应用中,HTTP请求和响应是如何实现的,通常我们使用AJAX模式,来替换过去的简单页面请求的方式,来实现更灵活高效的HTTP Web应用。
AJAX
AJAX全称是Asynchronous Javascript And XML,异步的Javascript和XML,这个描述其实是相当的精当。这个异步的意思就是,在页面加载完成之后,可以在某个合适的时间,按照需要再次(异步)通过Javascript来发起请求,从服务器获取XML内容,然后进行后续的处理。
典型的AJAX请求过程的结构和代码如下:
const xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("demo").innerHTML =
this.responseText;
}
};
xhttp.open("GET", "ajax_info.txt");
xhttp.send();
这里可以看到AJAX是浏览器通过XMLHttpRequest这个类和相关技术实现的。它就是所谓的XML内容的HTTP请求,但这个提法其实过于片面,实际上现有的请求方法有很大的可自定义性,并没有限制在XML上。
这个对象的相关方法和属性的定义如下表,笔者觉得稍微深入讨论一下这些内容,非常有助于我们理解浏览器是如何构造和我们可以如何处理异步请求,甚至通用的HTTP请求的。
方法和属性 | 描述信息 |
---|---|
new XMLHttpRequest() | 创建新XMLHttpRequest对象实例 |
abort() | 取消当前请求 |
getAllResponseHeaders() | 获取相应头信息 |
getResponseHeader() | 获取特定相应头信息 |
open(method, url, async, user, psw) | 打开HTTP连接 |
setRequestHeader() | 设置请求头信息 |
send() | 发送请求, GET方法 |
send(string) | 发送请求和数据,POST方法 |
onload | 定义响应回调函数 |
onreadystatechange | 定义准备状态变化的回调函数 |
responseText | 响应数据,文本形式 |
responseXML | 响应数据,XML形式 |
readyState | 准备状态 |
status | HTTP规范请求状态码 |
statusText | 请求状态信息,对应状态码 |
其中,准备状态(readyState)包括:
0: 请求对象未初始化
1: 服务器连接已建立
2: 请求已被接收
3: 请求正在处理
4: 请求结束,响应已就绪
open方法参数包括:
method: 请求类型,GET或者POST
url: 请求地址
async: 是否同步(true/false)
user: 可选用户名
psw: 可选密码
可以看到,通过这个对象,基本上可以通过程序来控制和操作一个完整的HTTP请求和响应的过程,相比原来只能通过链接和表单来实现的请求/响应过程,无疑提供了很大的灵活性。这是一个巨大的技术改进,使原来的以“页面”构成的应用模式,真正的进化为“数据”驱动的Web应用。
此外,我们也可以清晰的看到,这个AJAX只是在操作层面(浏览器的实现和处理机制)进行了改进,其实和HTTP协议本身,是没有关系的。
其他HTTP方法
除了我们前面讨论并且熟悉的GET和POST方法。HTTP还定义了其他一些方法,虽然用的不多,这里就简单了解一些。
- DELETE 删除
是的,删除资源应该使用DELETE方法。可能是觉得处理麻烦,实际实现中都使用POST。
- PUT 放置
这个方法的语义用于更新资源(对,HTTP规范就是这样定义的),意思是需要改变原有的资源。和我们熟知的POST有一点点概念上的差异,但一般的开发者和开放框架为了简单起见,都予以忽略,直接使用POST。
- PATCH 补丁
可以理解成PUT的改进版本,它可以只更新资源的一部分。但主要是在语义上的细微差异,实际使用的比较少。
- HEAD 头
它是GET方法的一个特例,告诉服务器可以只响应头信息,而不需要响应内容。可以作为预请求来检测和评估服务器可能的响应。
- OPTIONS 选项
此方法用于询问Web服务器某个指定URL支持哪些HTTP请求方法的。服务器或在Allow头信息中响应结果。用于功能检测。
- CONNECT 连接
此方法用于通过代理服务器建立和目标服务器的隧道连接。
- TRACE 跟踪
有点像TCP的trace命令,用于测试或者诊断代理服务器链路。
上面就是HTTP官方规范的请求方法。作为一个开放的协议,笔者猜想,开发者也是是可以自己定义HTTP方法的。但问题是,那就要完全自定义的来构造客户端请求所使用的指令和服务端处理这些指令。在一般情况下原来的定义就已经足够使用,所以这些自定义其实是没有必要的。
HTTP响应状态
笔者觉得,HTTP响应状态和编码体系也是一个非常精妙的设计,其实对很多业务和应用系统的设计和开发也有参考意义,比如笔者的一些系统的业务状态代码,就直接借鉴了HTTP状态编码和语义。这里也简单的研究和探讨一下。
简单而言,HTTP状态码就是用于标识在HTTP请求和响应过程中的各种状态的编码和语义信息,特别是针对各种正常状态的处理,它可以帮助客户端或者应用程序来进行正确的后续处理。
HTTP响应状态非常多,但其实常见的就只有几种,这里简要的说明一下:
- 200 OK: 一切正常
- 401 Auth: 看到这个,客户端就知道需要进行认证,浏览器通常就会跳出认证对话框
- 403 Forbidon: 无权访问资源
- 404 Not Found: 通常表示告知客户端所请求的资源未找到
- 500 Server Error: 服务器错误,一般在应用服务器程序处理错误,会给一个模糊的错误信息
其实,完整的HTTP协议对于HTTP过程状态,是有比较完整的定义的。其设计也是有相关规则的,如:
- 100+:表示响应的信息
- 200+:成功的响应
- 300+:重定向信息
- 400+:客户端的错误响应,如授权,非正常的请求等等
- 500+: 服务端的错误响应
- 600+:这里就可以自定义了,因为HTTP规范没有这个内容?
头信息
另一个作为开发者需要了解甚至熟悉的内容就是HTTP的头信息了。从某种意义上而言,这个头信息其实是比具体内容更重要的信息,因为它直接决定和控制客户端和服务端如何协商处理请求和响应的过程。这里是一些常用标准的头信息项目,还有一些是笔者觉得比较有趣,让读者可以理解一些HTTP应用和功能实现细节的项目:
- Content-Type: 内容类型
用于声明内容的类型和格式,让对方能够正确的进行处理。这个使用MIME格式,常见的内容包括:
text/html; charset=utf-8 (HTML页面和字符集)
application/x-www-form-urlencoded (默认POST表单提交使用的类型)
application/json (常见的数据格式,使用JSON,XML现在比较少用了)
image/png (图片和格式)
application/octstream (通用二进制文件或者数据流)
- Allow
服务器告诉客户端,可以使用的HTTP方法,通常在Option方法,或者响应中随405(Method Not Allow)出现。
- Content-Length
内容编码后的字节数,可以让对方预先知道内容的大小,进行相关准备,并且知道如何结束数据接收。
- Connection: keep-alive 保持连接
告诉对方请求发送后,保持TCP连接开启。这个对于性能非常重要,因为可以减少重复建立TCP连接的过程,这也是HTTP1.1的最重要的改进(知错快改)。
- Host
请求时所使用的主机域名,服务器使用这个头信息,可以用于实现虚拟主机的服务,在一台实际的主机和HTTP服务实例上,提供多个HTTP域名主机的服务。
- Set-Cookie: cookie-name=cookie-value; Domain=domain-value
这就是Cookie的实现方式。服务器使用此方法可以传递一些配置或者控制信息给客户端。随后,浏览器会在后续的请求中,自动添加这些内容到请求头信息中,来实现某种程度的会话管理和状态共享。
- Server
可选由服务器告知客户端其技术实现方式和版本。现在通常认为这是一个安全隐患,因为暴露了服务器的技术体系,让攻击者可以收集信息并且采用有针对性的攻击方案。
- Referer: url
向服务器声明,此请求来自那个页面或者地址,可以提高安全性。很多图片防盗链服务就基于这个机制,请求时不能单独请求,必须指定发起请求的页面。
- Range: unit=range-start-range-end, range-start-range-end
请求一个资源的片段,可以指定所使用的计量单位,起始点和结束点。这就是很多“断点续传”和“多线程”下载软件实现的原理,它可以发起多个请求,每个请求都设置不同的范围,达到并非下载,或者不从头开始下载的目的。
- User-Agent
在HTTP规范的技术术语中,浏览器叫做用户代理,通常在请求时浏览器会将这个信息附加到请求头中
- Accept, Accept-Encoding, Accept-Language
告诉服务器可以接收何种类型的信息,编码压缩方式或者语言。
- Cache-Control
缓存控制方式,如果希望强行刷新内容,可以设置为no-cache。
- ETag
用于在响应时,标识一个资源的版本,通常用于缓存控制。
- Upgrade
HTTP协议,也是可以选择升级或者切换的,如基于HTTP协议来使用WebSocket协议,就需要使用这个指令来进行升级和切换(响应状态101)。
总结
写到这里,虽然还有很多没有涉及和深入的内容,但相信读者对于HTTP也已经可以一个比较全面和立体的理解了。完整的内容可以参考其标准网站:
httpwg.org/specs/
其实HTTP协议的核心本身并不复杂,更多的是一种规范和思维的逻辑框架。但就是因为它的简单、合理、科学,才能够奠定我们现在整个Web世界的技术基础。其实在日常的应用和业务设计上,它也能够给我们很多帮助和启示。随着需求和技术的发展,HTTP2和HTTP3改进了很多传输控制方面的内容,但起码到现在,其核心理念和逻辑框架还是不变的。对HTTP协议的了解得越多,对HTTP协议使用的越正确合理,对HTTP应用的开发和使用的帮助也会越大。