HTTP协议到底是什么,干什么用的?
Roy Fielding在其REST论文(中文翻译版)6.3节中,是这么定义的:
超文本移交协议(HTTP)在Web架构中有一个特殊的角色,它既作为Web组件之间通信的主要的应用级协议,也是作为特别为移交资源的表述而设计的唯一协议。
(注:Fielding发布REST论文是在2000年,而在2014年又诞生了一个COAP移交协议,所以从现在时间点来看,HTTP已经不是唯一的移交协议了。)
HTTP(HyperText Transfer Protocol)是关于移交的协议(transfer protocol),不是关于传输的协议(transport protocol),TCP才是关于传输的协议。移交意味着某个东西在抽象层面上从一个角色转移给了另一个角色。传输意味着某个东西在物理层面上从一个地点转到了另一个地点。非常不幸,HTTP协议刚传入我国时,即被翻译为“超文本传输协议”,因为“transport”和“transfer”在中文中都具有“传输”的含义,之后以讹传讹贻害无穷。
(一)设计的角度
从设计的角度看,HTTP的作用是让客户端和服务端按照一个标准的流程、格式来移交资源的表述。具体表现为:
客户端
- 通过URI说明要移交的表述属于【哪个资源】
- 通过HTTP请求把资源的表述移交给服务端
- 通过HTTP动词说明要求服务端对该资源采取【哪种操作】
服务端
- 通过HTTP响应将客户端需要的表述或操作结果移交给客户端。
一篇文章是一个资源,可以有中文、英文等不同语言的形态,也可以有HTML、TXT、PDF等不同格式的形态,还可以根据文章内容的变化有不同版本的形态,即一个资源是其所有形态的集合。
URI:统一资源标识符,唯一地标识了一个形态集合。
- 当URI标识的是由多个子资源组合成的大资源时,例如所有今日发表的文章,集合的元素是各个子资源的URI。
- 当URI标识的是无法再分割的资源时,例如一篇文章,集合的元素是资源的各个形态。
表述:是资源的当前状态或预期状态。从实现的角度来看,表述由原始数据(字节形态的HTML、JPEG图片)、表述元数据(媒体类型、最后修改时间)、资源元数据(source link、alternates、vary)、控制数据(if-modified-since、cache-control)组成。
- 增:当用户将一篇TXT、中文的文章发布到网站上时,用户代理将资源的当前状态(TXT、中文的文章)移交给来源服务器。
- 查:当用户想要浏览HTML、英文形态的文章时,用户代理表明所需资源的预期状态,来源服务器将资源的预期状态(HTML、英文的文章)移交给用户代理。
- 改:当用户想修改文章内容时,用户代理将资源的当前状态(新版本的文章)移交给来源服务器。
- 删:当用户想删除文章时,用户代理将资源的当前状态(内容为空也是一种新版本)移交给来源服务器。
HTTP动词:GET、POST、PUT、DELETE等。
在实操中,经常会见到增删改查4个功能都是POST请求的Web应用。既然一个POST动词就能实现所有功能,HTTP为什么还要设计GET、PUT、DELETE等动词?其目的是通过不同的动词来区分操作的安全性,使得操作的安全性对中间组件可见,例如防火墙能够直接根据动词来过滤不安全的操作。GET是安全、幂等的操作,PUT和DELETE都是不安全、但幂等的操作,POST是既不安全、又不不幂等的操作。
(二)实现的角度
客户端和服务端只是笼统的角色名称,这个移交的过程是由多个Web组件动态连接成过滤管道来具体实现的。因此,从实现的角度看,HTTP的作用是提供组件交互的统一接口(注:HTTP和URI两个规范加在一起完整定义了组件交互的接口)。
组件是过滤管道中的各种角色。
- 客户端组件:用户代理。例如:chrome等各种浏览器、爬虫等。
- 中间组件:既是客户端组件,又是服务端组件,具体分为网关、代理、防火墙。例如:网关CGI、代理CERN。
- 服务端组件:来源服务器。例如:Apache httpd、Ngnix、IIS。
连接器是用于组件之间进行交互的机制,组件借助连接器与其他组件进行交互。
- 位于客户端的连接器:缓存型连接器chrome cache、客户型连接器httpclient。
- 位于中介方的连接器:解析型连接器DNS、隧道型连接器SSL。
- 位于服务端的连接器:服务型连接器Apache api。
移交是如何实现的?
用户代理(chrome)首先使用缓存型连接器(chrome cache)查找是否有已缓存的响应,找不到则使用客户型连接器(httpclient)与本地代理中间组件进行交互,通过HTTP请求将表述移交给本地代理,本地代理使用解析型连接器(DNS)与网关中间组件(CGI)进行交互,将表述移交给了网关,网关使用服务型连接器(Apache api)与来源服务器(Apache httpd)进行交互,表述被移交给了来源服务器,它再通过HTTP响应将表述逐步移交给用户代理。
为什么Web交互要采用统一接口?
根据Roy Fielding 的REST论文(中文翻译版)的5.1.5 节 :
采用统一接口给Web架构带来的好处:
- 简化了整体的系统架构。
- 改善了交互的可见性。
- 各个组件的具体实现与其所提供的服务是解耦的,促进了它们的独立可进化性。
采用统一接口给Web架构造成的代价:
- 降低了效率,因为信息都是使用标准的形式来移交的,而不是特定于应用需求的形式。
什么样的接口最适合作为Web交互的统一接口?
根据Roy Fielding 的REST论文(中文翻译版)的5.1.5 节 :
HTTP和URI这两个规范合起来定义了组件在Web上交互时需遵循的接口标准,这些接口标准是针对Web场景需求做了专门优化的,因此它们是Web架构的最优选择,但对于其他非Web架构而言并不是最优的。
HTTP和URI定义的接口标准可以归纳为4个约束条件,称为【统一接口约束】,符合它的接口称为RESTful API:
- 资源的识别:通过URI唯一标识一个资源。
- 通过表述操作资源:通过HTTP请求移交表述,通过HTTP动词表明操作。
- 自描述的消息:HTTP中包含有资源的元数据,表述的元数据的header,URL中包含资源的标识。
- HATEOAS:超媒体作为应用程序状态的引擎(详见 2.4 REST关于应用状态的模型)。
当所有组件都遵循上述4个约束条件来设计具体接口时,整个Web就形成了一套通用的统一接口,从而能够改善Web架构的简单性、交互的可见性、组件的独立可进化性。