从http简介到网络分层及web架构
浏览器发起HTTP请求的典型场景
a stateless application-level request/response protocol that uses extensible semantics and self-descriptive message payloads
for flexible interaction with network-based hypertext information systems(RFC7230 2014.6)
一种无状态的、应用层的、以请求/应答方式运行的协议,它使用可扩展的语义和自描述消息格式,与基于网络的超文本信息系统灵活的互动
HTTP协议格式
ABNF(扩充巴科斯-瑙尔范式)
ABNF(扩充巴科斯-瑙尔范式)操作符
ABNF(扩充巴科斯-瑙尔范式)核心规则
基于ABNF描述的HTTP协议格式
OSI(Open System Interconnection Reference Model)概念模型
OSI 模型与TCP/IP模型对照
报文头部在OSI 模型与TCP/IP模型传输
评估Web架构的关键属性
架构属性:性能
架构属性:可修改性
REST架构下的Web
WAIS 知识点补充
WAIS 是一个Internet系统,在这个系统中,需要在多个服务器上创建专用主题数据库,该系统可以通过服务器目录对各个服务器进行跟踪,并且允许用户通过WAIS客户端程序对信息进行查找。
WAIS用户可以获得一系列的分布式数据库,当用户输入一个对某一个数据库进行查询的信息时,客户端就会访问所有与该数据库相关的服务器。
访问的结果提供给用户的是满足要求的所有文本的描述,此时用户就可以根据这些信息得到整个文本文件了。
WAIS使用的是自己的Internet,这个<协议是Z39.50标准(国际信息标准组织制定的标准)的扩展。
Web用户可以下载一个WAIS客户机程序和一个“网关”到Web浏览器,或者通过远程登录,连接到一个公共的WAIS客户机,这样就可以使用WAIS了。
由于丰富的服务器文件以及搜索引擎现已存在,所以大多数的Web用户将会觉得WAIS是多余的。
但是,对于图书管理员、医学研究员还有其他一些人,他们可以通过WAIS可以得到一些在现有Web上没有的专业信息。
5种架构风格
数据流风格 Data-flow Styles
管道和过滤器(Pipe and Filter,PF)
每个组件(过滤器)从其输入端读取数据流并在其输出端产生数据流,通常对输入流应用一种转换并增量地处理它们,以使输出在输入被完全处理完之前就能够开始。这种风格也被称作单路数据流网络(one-way data flow network)。
统一管道和过滤器(Uniform Pipe and Filter,UPF)
该风格在 PF 风格的基础上,添加了一个约束,即所有过滤器必须具有相同的接口。
复制风格Replication Styles
复制仓库(Replicated Repository,RR)
基于复制仓库风格的系统通过利用多个进程提供相同的服务,来改善数据的可访问性和服务的可伸缩性。
这些分散的服务器交互为客户端制造出只有一个集中的服务的“幻觉”。主要的例子包括诸如 XMS 这样的分布式文件系统和 CVS这样的远程版本控制系统。
缓存(Cache,$)
复制仓库风格的一种变体是缓存风格,复制个别请求的结果,以便可以被后面的请求重用。
分层风格Hierarchical Styles
客户-服务器(Client-Server,CS)
该风格在基于网络的应用的架构风格中最为常见。服务器组件提供了一组服务,并监听对这些服务的请求。客户端组件通过一个连接器将请求发送到服务器,希望执行一个服务。服务器可以拒绝这个请求,也可以执行这个请求并将响应发送回客户端。
分层系统(Layered System,LS)
一个分层系统是按照层次来组织的,每一层为在其之上的层提供服务,并且使用在其之下的层所提供的服务。尽管分层系统被看作一种“单纯”的风格,但是它在基于网络的
系统中的使用仅限于与客户-服务器风格相结合,形成分层-客户-服务器风格。分层系统的例子包括分层通信协议的处理,例如 TCP/IP 和OSI 协议栈。
分层-客户-服务器(LayeredClient-Server,LCS)
该风格在客户-服务器风格的基础上添加了代理(proxy)组件和网关(gateway)组件。一个代理组件作为一个或多个客户端组件的共享服务器,它接收请求并进行可能的转换后将其转发给服务器。一个网关组件在客户端或代理看起来像是一个正常的服务器,但是事实上它将请求进行可能的转换后转发给了它的“内部层”(inner- layer)服务器。这些额外的中间组件添加了很多个层,用来为系统添加诸如负载均衡和安全性检查这样的功能。
客户-无状态-服务器(Client-Stateless-Server,CSS)
该风格源自客户-服务器风格,并且添加了额外的约束:在服务器组件之上不允许有会话状态(session state)。从客户端发到服务器的每个请求必须包含理解请求所必需的全部信息,不能利用任何保存在服务器上的上下文(context),会话状态全部保存在客户端。
客户-缓存-无状态-服务器(Client-Cache-Stateless-Server,C$SS)
该风格来源于客户-无状态-服务器风格和缓存风格(通过添加缓存组件)。
分层-客户-缓存-无状态-服务器(Layered-Client-Cache-StatelessServer,LC$SS)
该风格通过添加代理或网关组件,继承了分层-客户-服务器风格和客户-缓存-无状态-服务器风格。使用此风格的范例系统是 Internet 域名系统(DNS)。
远程会话(Remote Session,RS)
该风格是客户-服务器风格的一种变体,它试图使客户端组件(而非服务器组件)的复杂性最小化或者使得它们的可重用性最大化。每个客户端在服务器上启动一个会话,然后调用服务器的一系列服务,最后退出会话。应用状态被完全保存在服务器上。这种风格通常在以下场合中使用:想要使用一个通用的客户端(例如 TELNET)或者通过一个模仿通用客户端的接口(例如 FTP )来访问远程服务。
远程数据访问(Remote Data Access,RDA)
该风格是客户-服务器风格的一种变体,它将应用状态分布在客户端和服务器上。客户端以一种标准的格式发送一个数据库查询(例如 SQL)请求到服务器,服务器分配一个工作空间并执行这个查询,这可能会导致一个巨大的结果集。客户端能够在结果集上进行进一步操作(例如表连接)或者每次获取结果的一部分。客户端必须了解服务的数据结构,以便建造依赖于该结构的查询。
移动代码风格 Mobile Code Styles
虚拟机(Virtual Machine,VM)
所有移动代码风格的基础是虚拟机(或解释器)风格。代码必须以某种方式来执行,首选的方式是在一个满足了安全性和可靠性关注点的受控环境中执行,而这正是虚拟机风格所提供的。
远程求值(Remote Evaluation,REV)
该风格来源于客户-服务器风格和虚拟机风格,一个客户端组件必须要知道如何来执行一个服务,但缺少执行此服务所必需的资源(CPU 周期、数据源等等),这些资源恰好位于一个远程站点上。因此,客户端将如何执行服务的代码发送给远程站点上的一个服务器组件,服务器组件使用可用的资源来执行代码,然后将执行结果发送回客户端。
按需代码(Code on Demand,COD)
在该风格中,一个客户端组件知道如何访问一组资源,但不知道如何处理它们。它向一个远程服务器发送对于如何处理资源的代码的请求,接收这些代码,然后在本地执行这些代码。
分层-按需代码-客户-缓存-无状态-服务器(Layered-Code-on-DemandClient-Cache-Stateless-Server,LCODC$SS)
将按需代码风格添加到上面讨论过的分层-客户-缓存-无状态-服务器风格上。因为代码被看作不过是另一种数据元素,因此这并不会妨碍LC$SS 风格的优点。
移动代理(Mobile Agent,MA)
在该风格中,一个完整的计算组件,与它的状态、必需的代码、执行任务所需的数据一起被移动到远程站点。该风格可以看作来源于远程求值风格和按需代码风格,因为移动性是同时以这两种方式工作的。
点对点风格Peer-to-Peer Styles
基于事件的集成(Event-based Integration,EBI)
该风格不是直接调用另一个组件,而是一个组件能够发布(或广播)一个或者多个事件。在事件发布后,系统中的其他组件能够注册对于某些事件类型的兴趣,由系统本身来调用所有已注册的组件。
C2
C2 架构风格直接支持大粒度的重用,并且通过加强底层独立性,支持系统组件的灵活组合。它通过将基于事件的集成风格和分层-客户-服务器风格相结合来达到这些目标。
异步通知消息向下传送,异步请求消息向上传送,这是组件之间通信的唯一方式。这加强了对高层依赖的松散耦合(服务请求可以被忽略),并且与底层实现了零耦合(不知道使用了通知),从而改善了对于整个系统的控制,又没有丧失EBI 的大多数优点。
分布式对象(Distributed Objects,DO)
该风格将系统组织为结对进行交互的组件的集合。一个对象是一个实体,这个实体封装了一些私有的状态信息或数据、操作数据的一组相关的操作或过程、以及一个可能存在的控制线程,这种封装使得它们能够被整体地看作单个的单元。
通常,一个对象的状态对于所有其他对象而言,是完全隐藏和受到保护的。检查或修改对象状态的唯一方法是对该对象的一个公共的、可访问的操作发起请求或调用。
这样就为每个对象创建了一个良好定义的接口,在对象的操作实现和它的状态信息保持私有的同时,公开操作对象的规格,这样做改善了可进化性。
被代理的分布式对象(Brokered Distributed Objects,BDO)
该风格引入了名称解析组件——其目的是将该组件接收到的客户端请求中一个通用的服务名称解析为一个能够满足该请求的对象的特定名称,并使用这个特定名称来答复客户端。
为了降低对象标识的影响,现代分布式对象系统通常使用一种或更多种中间风格(intermediary styles)来辅助通信。这包括基于事件的集成风格和被代理的客户/服务器(brokered client/server)风格。
被代理的分布式对象风格引入了名称解析组件——其目的是将该组件接收到的客户端请求中一个通用的服务名称解析为一个能够满足该请求的对象的特定名称,并使用这个特定名称来答复客户端。
尽管它改善了可重用性和可进化性,但额外的间接层要求额外的网络交互,这降低了效率和用户可觉察的性能。
知识点补充C2:
C2体系结构风格可以概括为:通过连接件绑定在一起的按照一组规则运作的并行构件网络。C2风格中的系统组织规则如下:
(1)系统中的构件和连接件都有一个顶部和一个底部;
(2)构件的顶部应连接到某连接件的底部,构件的底部则应连接到某连接件的顶部,而构件与构件之间的直接连接是不允许的;
(3)一个连接件可以和任意数目的其它构件和连接件连接;
(4)当两个连接件进行直接连接时,必须由其中一个的底部到另一个的顶部。
C2风格的体系结构
C2风格是最常用的一种软件体系结构风格。从C2风格的组织规则和结构图中可以得知C2风格具有以下特点:
(1)系统中的构件可实现应用需求,并能将任意复杂度的功能封装在一起;
(2)所有构件之间的通讯是通过以连接件为中介的异步消息交换机制来实现的;
(3)构件相对独立,构件之间依赖性较少。系统中不存在某些构件将在同一地址空间内执行,或某些构件共享特定控制线程之类的相关性假设。
REST架构风格
REST是Web自身的架构风格。REST也是Web之所以取得成功的技术架构方面因素的总结。REST是世界上最成功的分布式应用架构风格(成功案例:Web)。
它是为“运行在互联网环境”的“分布式”“超媒体”系统量身定制的。互联网环境与企业内网环境有非常大的差别,最主要的差别是两个方面:
-
可伸缩性需求无法控制:并发访问量可能会暴涨,也可能会暴跌。
-
安全性需求无法控制:无法控制客户端发来的请求的格式,很可能会是恶意的请求。
而所谓的“超媒体系统”,即,使用了超文本的系统。可以把“超媒体”理解为超文本+媒体内容。
REST是HTTP/1.1协议等Web规范的设计指导原则,HTTP/1.1协议正是为实现REST风格的架构而设计的。新的Web规范,其设计必须符合REST的要求,否则整个Web的体系架构会因为引入严重矛盾而崩溃。
REST是所有Web应用都应该遵守的架构设计指导原则。
表述性状态转移(REST)风格是对分布式超媒体系统中的架构元素的一种抽象。
REST忽略了组件实现和协议语法的细节,以便聚焦于以下几个方面:
- 组件的角色
- 组件之间的交互之上的约束
- 组件对重要数据元素的解释
REST包括了一组对于定义 Web 架构基础的组 件、连接器和数据的基本约束,因此它代表了基于网络的应用的行为的本质。
REST提供了一组架构约束,当作为一个整体来应用时,强调组件交互的可伸缩性、接口的通用性、 组件的独立部署、以及用来减少交互延迟、增强安全性、封装遗留系统的中间组件。
REST架构风格最重要的架构约束有6个:
-
客户-服务器(Client-Server)
通信只能由客户端单方面发起,表现为请求-响应的形式。
-
无状态(Stateless)
通信的会话状态(Session State)应该全部由客户端负责维护。
-
缓存(Cache)
响应内容可以在通信链的某处被缓存,以改善网络效率。
-
统一接口(Uniform Interface)
通信链的组件之间通过统一的接口相互通信,以提高交互的可见性。
-
分层系统(Layered System)
通过限制组件的行为(即,每个组件只能“看到”与其交互的紧邻层),将架构分解为若干等级的层。
-
按需代码(Code-On-Demand,可选)
支持通过下载并执行一些代码(例如Java Applet、Flash或JavaScript),对客户端的功能进行扩展。
REST的架构元素。
1.数据元素(Data Elements)
1.1资源和资源标识符(Resources and Resource Identifiers)
REST对于信息的核心抽象是资源。资源是一种看待服务器的方式,即,将服务器看作是由很多离散的资源组成。
它不仅仅能代表服务器文件系统中的一个文件、数据库中的一张表等等具体的东西,可以将资源设计的要多抽象有多抽象,只要想象力允许而且客户端应用开发者能够理解。
与面向对象设计类似,资源是以名词为核心来组织的,首先关注的是名词。一个资源可以由一个或多个URI来标识。
URI既是资源的名称,也是资源在Web上的地址。对某个资源感兴趣的客户端应用,可以通过资源的URI与其进行交互。
REST使用一个资源标识符来标识组件之间交互所涉及到的特定资源。
1.2表述(Representations)
REST组件通过以下方式在一个资源上执行动作:使用一个表述来捕获资源的当前的或预期的状态、在组件之间传递该表述。一个表述是一个字节序列,以及描述这些字节的表述元数据。
表述的其他常用但不够精确的名称包括:文档、文件、HTTP 消息实体、实例或变量。表述的数据格式被称为一种媒体类型。源的表述可以有多种格式,例如HTML/XML/JSON/纯文本/图片/视频/音频等等。
资源的表述格式可以通过协商机制来确定。请求-响应方向的表述通常使用不同的格式。
2.连接器(Connectors)
REST使用多种不同的连接器类型来对访问资源和转移资源表述的活动进行封装。连接器代表了一个组件通信的抽象接口,通过提供清晰的关注点分离、 并且隐藏资源的底层实现和通信机制,从而改善了架构的简单性。接口的通用性也使得组件 的可替换性成为了可能:如果用户对系统的访问仅仅是通过一个抽象的接口,那么接口的实现就能够被替换,而不会对用户产生影响。由于组件的网络通信是由一个连接器来管理的,所以在多个交互之间能够共享信息,以便提高效率和响应能力。
3.组件(Components)
REST 组件根据它们在整个的应用动作中的角色来进行分类。
REST的5个关键词与6个主要特征
5个关键词
-
资源(Resource)
-
资源的表述(Representation)
-
状态转移(State Transfer)
-
统一接口(Uniform Interface)
-
超文本驱动(Hypertext Driven)
资源和资源的表述上一节已经补充
状态转移
状态转移(state transfer)与状态机中的状态迁移(state transition)的含义是不同的。状态转移说的是:在客户端和服务器端之间转移(transfer)代表资源状态的表述。通过转移和操作资源的表述,来间接实现操作资源的目的。
统一接口
REST要求,必须通过统一的接口来对资源执行各种操作。对于每个资源只能执行一组有限的操作。以HTTP/1.1协议为例,HTTP/1.1协议定义了一个操作资源的统一接口,主要包括以下内容:
-
7个HTTP方法:GET/POST/PUT/DELETE/PATCH/HEAD/OPTIONS
-
HTTP头信息(可自定义)
-
HTTP响应状态代码(可自定义)
-
一套标准的内容协商机制
-
一套标准的缓存机制
-
一套标准的客户端身份认证机制
REST还要求,对于资源执行的操作,其操作语义必须由HTTP消息体之前的部分完全表达,不能将操作语义封装在HTTP消息体内部。这样做是为了提高交互的可见性,以便于通信链的中间组件实现缓存、安全审计等等功能。
超文本驱动
“超文本驱动”又名“将超媒体作为应用状态的引擎”(Hypermedia As The Engine Of Application State,来自Fielding博士论文中的一句话,缩写为HATEOAS)。
将Web应用看作是一个由很多状态(应用状态)组成的有限状态机。资源之间通过超链接相互关联,超链接既代表资源之间的关系,也代表可执行的状态迁移。
在超媒体之中不仅仅包含数据,还包含了状态迁移的语义。以超媒体作为引擎,驱动Web应用的状态迁移。通过超媒体暴露出服务器所提供的资源,服务器提供了哪些资源是在运行时通过解析超媒体发现的,而不是事先定义的。
从面向服务的角度看,超媒体定义了服务器所提供服务的协议。客户端应该依赖的是超媒体的状态迁移语义,而不应该对于是否存在某个URI或URI的某种特殊构造方式作出假设。一切都有可能变化,只有超媒体的状态迁移语义能够长期保持稳定。
6个主要特征:
-
面向资源(Resource Oriented)
-
可寻址(Addressability)
-
连通性(Connectedness)
-
无状态(Statelessness)
-
统一接口(Uniform Interface)
-
超文本驱动(Hypertext Driven)
这6个特征是REST架构设计优秀程度的判断标准。
其中,面向资源是REST最明显的特征,即,REST架构设计是以资源抽象为核心展开的。可寻址说的是:每一个资源在Web之上都有自己的地址。
连通性说的是:应该尽量避免设计孤立的资源,除了设计资源本身,还需要设计资源之间的关联关系,并且通过超链接将资源关联起来。
无状态、统一接口是REST的两种架构约束,超文本驱动是REST的一个关键词已经解释。
三种架构风格的比较
- 分布式对象(Distributed Objects,简称DO)
架构实例有CORBA/RMI/EJB/DCOM/.NET Remoting等等。
-
远程过程调用(Remote Procedure Call,简称RPC)
架构实例有SOAP/XML-RPC/Hessian/Flash AMF/DWR等等。
-
表述性状态转移(Representational State Transfer,简称REST)
架构实例有HTTP/WebDAV。
DO和RPC这两种架构风格在企业应用中非常普遍,而REST则是Web应用的架构风格,它们之间有非常大的差别。
REST与DO的差别在于:
-
-
REST支持抽象(即建模)的工具是资源,DO支持抽象的工具是对象。在不同的编程语言中,对象的定义有很大差别,所以DO风格的架构通常都是与某种编程语言绑定的。跨语言交互即使能实现,实现起来也会非常复杂。而REST中的资源,则完全中立于开发平台和编程语言,可以使用任何编程语言来实现。
-
DO中没有统一接口的概念。不同的API,接口设计风格可以完全不同。DO也不支持操作语义对于中间组件的可见性。
-
DO中没有使用超文本,响应的内容中只包含对象本身。REST使用了超文本,可以实现更大粒度的交互,交互的效率比DO更高。
-
REST支持数据流和管道,DO不支持数据流和管道。
-
DO风格通常会带来客户端与服务器端的紧耦合。在三种架构风格之中,DO风格的耦合度是最大的,而REST的风格耦合度是最小的。REST松耦合的源泉来自于统一接口+超文本驱动。
-
REST与RPC的差别在于:
-
-
REST支持抽象的工具是资源,RPC支持抽象的工具是过程。REST风格的架构建模是以名词为核心的,RPC风格的架构建模是以动词为核心的。简单类比一下,REST是面向对象编程,RPC则是面向过程编程。
-
RPC中没有统一接口的概念。不同的API,接口设计风格可以完全不同。RPC也不支持操作语义对于中间组件的可见性。
-
RPC中没有使用超文本,响应的内容中只包含消息本身。REST使用了超文本,可以实现更大粒度的交互,交互的效率比RPC更高。
-
REST支持数据流和管道,RPC不支持数据流和管道。
-
因为使用了平台中立的消息,RPC风格的耦合度比DO风格要小一些,但是RPC风格也常常会带来客户端与服务器端的紧耦合。支持统一接口+超文本驱动的REST风格,可以达到最小的耦合度。
-
比较了三种架构风格之间的差别之后,从面向实用的角度来看,REST架构风格可以为Web开发者带来三方面的利益:
-
简单性
采用REST架构风格,对于开发、测试、运维人员来说,都会更简单。可以充分利用大量HTTP服务器端和客户端开发库、Web功能测试/性能测试工具、HTTP缓存、HTTP代理服务器、防火墙。这些开发库和基础设施早已成为了日常用品,不需要什么火箭科技(例如神奇昂贵的应用服务器、中间件)就能解决大多数可伸缩性方面的问题。
-
可伸缩性
充分利用好通信链各个位置的HTTP缓存组件,可以带来更好的可伸缩性。其实很多时候,在Web前端做性能优化,产生的效果不亚于仅仅在服务器端做性能优化,但是HTTP协议层面的缓存常常被一些资深的架构师完全忽略掉。
-
松耦合
统一接口+超文本驱动,带来了最大限度的松耦合。允许服务器端和客户端程序在很大范围内,相对独立地进化。对于设计面向企业内网的API来说,松耦合并不是一个很重要的设计关注点。但是对于设计面向互联网的API来说,松耦合变成了一个必选项,不仅在设计时应该关注,而且应该放在最优先位置。
但是评价一种软件架构的优劣,不能脱离开软件的具体运行环境。永远不存在适用于任何运行环境的、包治百病的万能架构。REST是一种为运行在互联网环境中的Web应用而量身定制的架构风格。