服务开发
服务开发
Chapter-1:绪论
什么是服务
定义为在一个应用软件内部的一种方法、过程、或通讯。
旨在满足某些业务需求的应用程序的操作。
区别于系统的,服务一个或者一组相对较小且独立的功能单元,
用户可以感知最小功能集。
优势
服务每个模块就相当于一个单独的项目,代码量明显减少,遇到问题也相对来说比较好解决
服务每个模块都可以使用不同的开发技术,开发模式更灵活
服务强调结构上的“松耦合”,而在功能上则可以整合为一个统一的整体,可以实现有效的拆分应用,实现敏捷开发和部署
API帮助开发者
快速的应用开发与部署
多通道集成
敏捷的服务组合
内部和外部服务的市场
Web技术方案:从RPC到REST
web的基石
URI:地址
HTTP:传输
HyperText:表达(除了HTML外,也可以是带有超链接的XML或 JSON)
MIME:扩展
- 本意为多目的Internet邮件扩展,最初目的是为了在发送电子邮件时附加多媒体数据,让邮件客户程序能根据其类型进行处理。
- 当它被HTTP协议支持之后,它的意义就更为显著了。它使得HTTP传输的不仅是普通的文本,而变得丰富多彩
常用的媒体类型(MIME)
text/html:HTML格式的文档
text/xml(application/xml):XML格式的文本
text/json(application/json): JSON格式的文本
image/gif(image/jpeg、image/png):GIF(JPEG、PNG)格式的图片
audio/mp4(audio/mpeg、audio/vnd.wave):MP4(MPEG、WAVE)格式的音频文件
video/mp4(video/mpeg、video/quicktime):MP4(MPEG、QUICKTIME)格式的视频文件
"text/json"和"application/json"都是表示JSON数据格式的MIME类型(Multipurpose Internet Mail Extensions)。
"text/json"是一种过时的MIME类型,它指示传输的内容是文本,并且是JSON格式的。但是,由于JSON数据可以包含非文本字符,例如二进制数据,因此"text/json"并不是最佳的MIME类型。
"application/json"是当前推荐使用的MIME类型。它指示传输的内容是JSON格式的数据,并且可以包含任何类型的数据,包括文本和二进制数据。
Http动词
GET:获取资源,请求指定的页面信息,并返回实体主体。
POST:提交数据,向指定资源提交数据进行处理请求(例如提交表单或上传文件)。数据被包含在请求体中。
PUT:更新资源,向指定资源位置上传最新内容,覆盖原始资源。
DELETE:删除资源,请求服务器删除指定的页面。
HEAD:获取报头信息,与GET方法类似,但是服务器不返回实体主体,只返回报头信息。
OPTIONS:获取资源支持的HTTP方法,请求查询服务器支持的HTTP方法。
REST
Rest 的宗旨是从资源的角度来观察整个网络,分布在各处的资源由URI确定,而客户端的应用通过URI来获取资源的表征。获得这些表征致使这些应用程序转变了其状态。随着不断获取资源的表征,客户端应用不断地转变着其状态
Rest语境下,Web应用的目的是将所拥有的的资源提供给资源请求者,资源请求者使用标准的HTTP协议请求资源
从RPC到ROA
XML-RPC
远程过程调用(remote procedure call,RPC)的分布式计算协议
通过XML将调用函数封装,并使用HTTP协议作为传送机制
XML-RPC透过向装置了这个协定的服务器发出HTTP请求
发出请求的用户端一般都是需要向远端系统要求呼叫的软件
这个标准慢慢演变成为今日的SOAP协定
SOAP
简单对象访问协议Simple Object Access Protocol
一种标准化的通讯规范,主要用于Web服务(web service)中
一个 SOAP 消息可以发送到一个具有 Web Service 功能的 Web 站点
数据是用一种标准化的可分析的结构来传递的,可以直接被第三方站点所利用
REST
表征状态转移(Representational State Transfer)
采用Web 服务使用标准的 HTTP 方法 (GET/PUT/POST/DELETE) 将所有 Web 系统的服务抽象为资源
从资源的角度来观察整个网络,分布在各处的资源由URI确定,而客户端的应用通过URI来获取资源的表征
对于各种资源的操作最后总是能抽象成为增删改查四种基本操作;在定义了定位资源的规则以后,对于资源的操作通过标准的Http协议就可以实现
组成RPC模式的Web服务核心
- 通讯:简单对象访问协议(SOAP)
- 提供了一个标准的封装结构,用来在各种不同的互联网协议(如SMTP、HTTP和FTP)上传输XML文档。
- 通过使用这样的标准消息格式,异构的中间件系统可以实现互操作
- 描述:Web服务描述语言(WSDL)
- 描述了接口,即Web服务支持的一系列标准格式的操作。它标准化了操作的输入和输出参数的表示以及服务的协议绑定,消息在线传输的方式。
- 使用WSDL,不同的客户端可以自动理解如何与Web服务交互
- 发布:通用描述、发现和集成(UDDI)
- 提供了一种通过搜索名称、标识符、类别或Web服务实现的规范来广告和发现Web服务的全局注册表
通用描述、发现和集成(UDDI,Universal Description, Discovery, and Integration)是一种基于Web服务的注册中心,它提供了一种标准的方式来描述、发现和集成Web服务。UDDI的主要目的是帮助企业和组织在Web上发布和发现Web服务,从而实现企业间的互操作性。
UDDI有三个主要组件:业务注册(Business Registration)、服务注册(Service Registration)和查询(Inquiry)。业务注册允许企业在UDDI注册中心注册自己的业务,包括企业名称、地址、联系人等信息。服务注册允许企业注册自己的Web服务,包括服务名称、服务描述、服务接口等信息。查询允许企业和组织通过UDDI注册中心查询和发现Web服务,以实现Web服务的集成和互操作。
UDDI是一种基于XML的标准,它定义了一组XML文档类型和API,用于描述、发现和集成Web服务。UDDI标准由OASIS(Organization for the Advancement of Structured Information Standards)组织制定和维护,目前已经成为Web服务的重要标准之一。
总之,UDDI是一种基于Web服务的注册中心,它提供了一种标准的方式来描述、发现和集成Web服务,帮助企业和组织在Web上发布和发现Web服务,从而实现企业间的互操作性。
RPC关键特点
RPC是一种面向操作的架构风格,RPC式架构的设计方法是把系统分解为一个个动作
在面向RPC的分析中,它会被视为将被客户端调用的动作(action)
本质上RPC架构的Web Service就是跨Web的过程调用,我们实现的是一个定制的操作,所有的开发和本地的没有什么区别,Web Service提供了跨Web的技术基础
回到ROA—REST风格的Web服务
REST是一种面向资源的架构风格
站在资源的角度思考应用,需要考虑的是
有哪些资源可供操作?这一点很重要,这是后续设计API的基础
资源如何表述?即请求者怎么要资源?提供者怎么给资源?
状态转移的条件?即什么时候改变资源?
REST vs. SOAP
REST对于资源型服务接口来说很合适,同时特别适合对于效率要求很高,但是对于安全要求不高的场景。
SOAP的成熟性可以给需要提供给多开发语言的,对于安全性要求较高的接口设计带来便利
REST(Representational State Transfer)和SOAP(Simple Object Access Protocol)都是用于构建分布式系统的Web服务协议,但它们在很多方面有所不同。
相同点:
- 都是用于构建分布式系统的Web服务协议。
- 都基于HTTP协议。
- 都使用XML作为数据交换格式。
不同点:
- REST是基于资源的,SOAP是基于操作的。REST的核心是资源,每个资源都有一个唯一的URI,而SOAP的核心是操作,每个操作都有一个唯一的操作名。
- REST使用HTTP的GET、POST、PUT、DELETE等方法来实现对资源的CRUD操作,而SOAP使用XML消息来实现对操作的调用。
- REST的消息体可以是XML、JSON、HTML等格式,而SOAP的消息体只能是XML格式。
- REST使用URL来定位资源,而SOAP使用XML命名空间来定位操作。
- REST的性能比SOAP更好,因为REST使用HTTP协议的缓存机制,而SOAP需要在每个消息中包含完整的描述信息。
- REST的设计更加简单,易于理解和实现,而SOAP的设计更加复杂,需要使用更多的标准和规范。
总之,REST和SOAP都有各自的优缺点,选择哪种协议取决于具体的应用场景和需求。
RESTful 服务的优势
- 使用统一的接口操作资源
- RESTful Web服务接口更易于使用,更加贴近 Web 本身的工作方式,也更加自然
- 无状态性,可伸缩性好,更易于负载均衡
- 安全操作与幂指相等特性
- HTTP 的 GET、HEAD 请求本质上应该是安全的调用
- HTTP 的 PUT、DELTE 调用,具有幂指相等特性 ,或称为幂等性(idempotent)
- RESTful Web 服务更容易实现缓存
- 更适合开放API场景
资源和表述
资源的本质
什么是资源
任何寄宿于Web可供操作的“事物”均可视为资源,就其本质而言,任何足够重要并被引用的事物都可以是资源。
信息系统中的资源一般是可以保存到计算机里面的虚拟资源,统称为“信息资源(information resource)”
信息资源可以看做是物理资源的一种抽象
某种意义上,这种资源抽象又具有物理含义
资源可以具有多种表现形式,这种资源的呈现形式,称作资源的表征(Representation)。
资源请求者和资源拥有者只有在对事物的命名上达成一致以后才能针对这个事物实现相互通信。因此,每个资源必须拥有自己的唯一标识,互联网中使用 URI 来唯一标记一个资源,包含了 URL 和 URN
URL(Uniform Resource Loader):统一资源定位符,侧重于 “定位” 二字。
URN(Uniform Resource Name):统一资源名称,侧重于 “命名” 二字。
表述的本质
从资源请求者的角度看,它并不关心资源是什么,因为它从来看不到资源,它看到的永远只是资源的URL和表述(Representation)。
在客户端-服务器端之间转移的,并不是资源本身,而是资源的表述,即就是资源当前状态的某种合适的表达。资源的表述,可以有多种格式,例如 json
/xml
/html
/纯文本等等
松耦合与前后端分离
一个松散耦合的系统中,客户端和远程服务并不知道,也不需要知道对方是如何实现的,这样他们各自的实现就可以根据需要进行更改,而不必担心会破坏对方已有的实现
前后端分离也已成为互联网项目开发的标准使用方式,前端所有用到的展现数据都是后端通过同步或异步接口方式提供,前端只负责展现,后端负责处理逻辑与数据的存储
通过资源的表述来间接完成交互,实际上就是隔离了客户端与服务端、前端与后端,使得请求服务的一方的操作不会直接影响到服务提供者,而服务提供者也可以安全地分享自己的资源
超媒体与HATEOAS
超文本(HyperText)
- 是用超链接的方法,将各种不同空间的文字信息组织在一起的网状文本,其中的文字包含有可以链接到其他文档的地址,以实现从当前阅读位置直接切换到超文本链接所指向的文本继续访问。
超媒体(HyperMedia)
- 是超级媒体的缩写。超媒体是一种采用非线性网状结构对块状多媒体信息(包括文本、图像、视频等)进行组织和管理的技术 。
- 超媒体在本质上和超文本是一样的,只不过超文本技术在诞生的初期管理的对象是纯文本,所以叫做超文本。
超媒体体现了一种“关联”关系
HATEOAS(超媒体策略
HATEOAS(Hypermedia as the Engine of Application State)是一种RESTful API设计原则,它强调在API中使用超媒体作为应用状态的引擎,以便客户端可以通过在响应中包含的链接来自动发现和使用API中的资源。
具体来说,HATEOAS要求API返回的响应中包含了指向其他相关资源的链接,这些链接可以让客户端发现和使用API中的其他资源。这些链接通常使用标准的超媒体格式来表示,以便客户端可以自动解析和使用这些链接。
使用HATEOAS可以使API更加灵活和易于使用,因为客户端不需要事先知道API中所有的资源和操作,而是可以通过响应中的链接来自动发现和使用这些资源和操作。这也使得API更容易演化和扩展,因为API的开发人员可以添加、删除或修改资源和操作,而不必担心客户端的兼容性问题。u只要能理解超媒体,REST客户端几乎不需要其他额外知识就能与应用程序或服务器进行交互.
总之,HATEOAS是一种强调使用超媒体作为应用状态引擎的RESTful API设计原则,它可以使API更加灵活、易于使用和演化。
Http操作
PATCH:根据提供的表述信息修改资源的部分状态。如果有某些资源状态在提供的表述中没被提到,这些状态就保持不变。PATCH类似于PUT,但允许对资源状态进行一些细粒度的改动
LINK:将其他资源连接到当前资源
UNLINK:销毁当前资源和其他某些资源的连接关系
DELETE
DELETE很明显不是一个安全的方法。发送一个DELETE请求的效果不同于未发送DELETE请求。但是DELETE方法有另外一个很有用的属性:它是幂等的(idempotent)
POST
POST-to-Append
POST-to-append,向某个资源发送一条POST请求用以在该资源的下一级中创送一个新的资源。当客户端发送一个POST-to-append请求的时候,它会在请求的实体消息体中添加所希望创建的资源的表述信息并发送给服务器
对POST-to-Append请求而言,最常见的响应码是201 (Created)它用于告知客户端一个新的资源已经创建成功。Location报头用于告诉客户端这个新资源的URL地址。另一种常见的响应码是202 (Accepted),这表示服务器打算按照提供的表述信息来创建一个资源,但是现在还没有真正创建完成
既不安全也不幂等
- 不安全:POST请求通常用于向服务器提交数据,因此POST请求可能会对服务器上的数据进行修改或创建新的资源,这使得POST请求不安全,因为它可能会对服务器上的数据造成影响。
- 不幂等:幂等是指对同一个资源的多次请求,结果应该是相同的,不会产生任何副作用。但是,POST请求不是幂等的,因为每次请求都会向服务器提交不同的数据,导致每次请求的结果都可能不同,而且每次请求都可能会对服务器上的数据进行修改或创建新的资源。
Overloaded POST
大部分浏览器只支持GET/POST方法,这使得我们无法完美的实现REST。对于这样的情况,大致有两种解决方法:
一种是在表单里加入一个_method之类名字的隐藏字段,用于表示真正的方法
另一种是使用X-HTTP-METHOD-OVERRIDE头信息来重载POST
可以将任何数据作为POST请求的一部分发送出去,不论是出于什么目的,这都是合法的。此时的POST并不真正表示“创建一个新的资源”,而是表示“任意而为(whatever)”这样POST请求实际上没有任何协议语义了(但肯定有动作语义/应用语义的)。将POST这种“任意而为(whatever)”用法称为重载的(overloaded) POST。因为一个重载的POST请求没有协议语义,你只能在应用语义的层面上来理解它
PUT
PUT vs. POST
创建操作可以使用POST,也可以使用PUT。区别在于POST是作用在一个集合资源之上的(/articles),而PUT操作是作用在一个具体资源之上的(/articles/123)
如果URL可以在客户端确定,那么就使用PUT。如果是在服务端确定,那么就使用POST
PATCH
PATCH请求是HTTP协议中的一种请求方法,用于对资源进行局部更新。与PUT请求不同的是,PATCH请求只需要更新资源的部分内容,而PUT请求则需要更新整个资源。PATCH请求通常用于更新资源的某些属性,而不是整个资源。在RESTful API设计中,PATCH请求被广泛应用于对资源的部分更新。
PATCH方法既不是安全的,也不能保证幂等
一个PATCH 请求有可能结果是等幂的,这种情况下,如果你不小心对同一个文档应用了两次patch,你可能会在第二次收到一个错误信息。但这并没有定义在相关标准中。考虑到PATCH的协议语义,它跟POST一样,是一个不安全的操作。
领域模型与领域驱动设计
领域与领域模型
任何一个系统都会属于某个特定的领域,而这个领域的核心业务是确定的,领域本质上可以理解为就是一个问题域。只要我们确定了系统所属的领域,那这个系统的核心业务,即要解决的关键问题、问题的范围边界就基本确定了
通过建立领域模型来描述领域中的核心问题,这就是模型驱动的思想。
领域驱动设计(DDD)
什么是域模型
域模型(domain model
)英文又称为问题域模型(problem space model
)。维基百科(Wikipedia
)对它的定义是A conceptual model of all the topics related to a specific problem
。 可以翻译成: “域模型是针对某个特定问题的所有相关方面的抽象模型”。 这个定义有几个要点:第一是“特定问题”, 也即是说域模型是针对性某个问题域而言的, 脱离的这个特定问题,域模型的构建其实不存在一个最优或者是最合理的构建。 第二是抽象, 域模型是一个抽象模型, 不是对某个问题的各个相关方面的一个映射, 也不是解决方案的构建。
关于域模型, 经常会看到大家把逻辑数据模型(logical data model
) 或者是物理数据模型(physical data model
)和域模型混为一谈。 甚至有同学把数据里的表结构抽取出来作为域模型来研究。 其实这是域模型的最大误区。 数据模型实质上都归属于结果域模型(solution space model
), 是对某个问题域的解决方案的一个描述, 实质上是对解决方案的一个具体描述。
另外一个常见的误区和领域驱动设计(DDD, Domain Driven Design
)有关。 我个人对DDD比较推崇, 但是DDD里提到的域模型实质上是结果域模型(Solution Space Model
), 不是问题域模型。 我在这个系列的文章里集中介绍的是问题域模型的构建, 而不是结果域模型的构建。这两者的区别在于前者的建立主要是为了统一我们对未知世界的了解, 也就是说我们需要统一思想, 搞清楚我们要解决什么问题和问题的本质。 而后者的主要是想解决针对近些年来敏捷开发模式中所普遍存在的对领域认知不完整而导致设计不合理的问题。 前者是一个对未知方向的探索过程,适用在一个相对较为模糊的命题,产出是对语言,边界和思路的统一。后者是一个方法论,适用于具体一个项目, 产出是一个项目的数据模型。
总结一下:(问题)域模型是为了准确定义需要解决问题而构造的抽象模型。特别值得强调的是域模型的功能是统一认知:对要解决的问题有一个完整,规范,并且是一致的认识。
DDD是什么
wiki释义:
领域驱动设计(英语:Domain-driven design,缩写 DDD)是一种通过将实现连接到持续进化的模型来满足复杂需求的软件开发方法。领域驱动设计的前提是:
- 把项目的主要重点放在核心领域(core domain)和域逻辑
- 把复杂的设计放在有界域(bounded context)的模型上
- 发起一个创造性的合作之间的技术和域界专家以迭代地完善的概念模式,解决特定领域的问题
领域驱动设计是一种由域模型来驱动着系统设计的思想,不是通过存储数据词典(DB表字段、ES Mapper字段等等)来驱动系统设计。领域模型是对业务模型的抽象,DDD是把业务模型翻译成系统架构设计的一种方式。
为什么建立一个领域模型是重要的
领域驱动设计告诉我们,在通过软件实现一个业务系统时,建立一个领域模型是非常重要和必要的,因为领域模型具有以下特点:
- 领域模型是对具有某个边界的领域的一个抽象,反映了领域内用户业务需求的本质;领域模型是有边界的,只反应了我们在领域内所关注的部分;
- 领域模型只反映业务,和任何技术实现无关;领域模型不仅能反映领域中的一些实体概念,如货物,书本,应聘记录,地址,等;还能反映领域中的一些过程概念,如资金转账,等;
- 领域模型确保了我们的软件的业务逻辑都在一个模型中,都在一个地方;这样对提高软件的可维护性,业务可理解性以及可重用性方面都有很好的帮助;
- 领域模型能够帮助开发人员相对平滑地将领域知识转化为软件构造;
- 领域模型贯穿软件分析、设计,以及开发的整个过程;领域专家、设计人员、开发人员通过领域模型进行交流,彼此共享知识与信息;因为大家面向的都是同一个模型,所以可以防止需求走样,可以让软件设计开发人员做出来的软件真正满足需求;
- 要建立正确的领域模型并不简单,需要领域专家、设计、开发人员积极沟通共同努力,然后才能使大家对领域的认识不断深入,从而不断细化和完善领域模型;
- 为了让领域模型看的见,我们需要用一些方法来表示它;图是表达领域模型最常用的方式,但不是唯一的表达方式,代码或文字描述也能表达领域模型;
- 领域模型是整个软件的核心,是软件中最有价值和最具竞争力的部分;设计足够精良且符合业务需求的领域模型能够更快速的响应需求变化;
DDD的主要任务
- 一是如何发现系统中的聚合(Aggregate)。所谓聚合是一组相关的领域对象(或者称为实体),是由业务和逻辑紧密关联的实体和值对象组合而成的
- 二是如何划分限界上下文(Bounded Context)
这两个元素可谓是DDD的核心概念,分别对应了单个业务功能模块内核心的领域对象,以及如何划分业务功能的边界。通过这种建模方法,可以方便开发者和领域专家更好的快速地配合进行开发
理解领域,识别资源,划分服务
理解领域
识别资源
资源即实体,实体即对象
- 这个对象代表的是业务对象,有明确的业务含义,类似供应商,采购订单,产品,合同等,这些业务对象正是我们在领域驱动设计时候经常会识别的领域对象
聚合用来封装真正的不变性,而不是简单地将对象组合在一起
- 聚合内有一套不变的业务规则,各实体和值对象按照统一的业务规则运行,实现对象数据的一致性,边界之外的任何东西都与该聚合无关,这就是聚合能实现业务高内聚的原因
聚合内数据强一致性,而聚合之间数据保持最终一致性,为实现服务内聚合之间的解耦,及以聚合为单位的服务组合和拆分,应避免跨聚合的领域服务调用和跨聚合的数据库表关联
划分服务
理想情况下,界限上下文与微服务可以一一对应,但在实际项目中,又会根据实际业务做一些灵活的调整,包括将多个界限上下文进行合并,对应的就是将相对简单的服务合并在一起;
但一般而言,聚合是服务的最小单元(一个界限上下文可以包括多个聚合),打破聚合,就很有可能破坏事务一致性和业务约束
如果粗粒度的体现业务价值的接口服务全部都变成了细粒度的数据库访问类细粒度接口服务,就会失去接口本身的意义,同时又将本身应该完全内聚在服务内部的业务逻辑全部暴露到外层去解决
在边界上定义接口
面向资源进行 RESTful 服务设计,资源的识别和定义可以参考领域设计的思路进行。
首先定义领域对象,将领域对象建模为对应的资源。
然后再考虑看这个资源应该暴露哪些能力接口出来。
REST成熟度模型
level 0:HTTP传输
只是使用 HTTP 作为传输方式(大多数是使用POST请求) 。这种方式可以理解为重载的POST,实际上所有的请求都是发往同一个服务端口(URI),请求的具体内容都在POST过去的文件中;这其实也是远程方法调用(RPC)的一种具体形式,XML-RPC和大多数SOAP服务都属于此类。
level 1:面向资源为中心
这一层级引入了资源的概念,并对每个资源都赋予了URI。但层级的所有请求也都是使用Post实现的。
level 2:利用 HTTP动词语义
本层级的服务使用 HTTP 语法来执行操作
level 3:利用超媒体控制
本层级的基本思想是资源通过超媒体描述自己的能力和连接关系,由GET请求返回的资源表示中包含资源能够执行操作的链接,这实际就是HATEOAS原则
设计只读的资源服务
设计过程
- 资源分析与设计
- 设计资源表述
- 把资源相互链接起来
- 规划服务交互的响应
ROA VS. RPC(前面铺垫过
ROA是一种基于资源的架构风格,它强调将资源作为系统的核心概念,以资源为中心来设计和实现系统。在ROA中,每个资源都有一个唯一的标识符(URI),并且可以通过HTTP协议中的GET、POST、PUT、DELETE等方法来对资源进行操作。
RPC是一种远程调用协议,它允许程序在不同的计算机或进程之间通过网络进行通信,实现像本地调用一样的远程调用。在RPC中,客户端通过调用远程服务端的函数来实现分布式系统的功能。
它们的主要不同点在于:
- ROA是基于资源的架构风格,而RPC是基于远程调用的协议。ROA强调将资源作为系统的核心概念,以资源为中心来设计和实现系统,而RPC则强调远程调用的过程。
- ROA使用HTTP协议中的方法来对资源进行操作,如GET、POST、PUT、DELETE等,而RPC使用自定义的协议和数据格式来实现远程调用。
- ROA通常使用RESTful API来实现,而RPC通常使用SOAP、XML-RPC、JSON-RPC等协议来实现。
- ROA更加灵活,可以支持多种数据格式和协议,而RPC则需要使用特定的协议和数据格式。
- ROA的优势在于它的资源导向设计,可以更好地支持多种客户端和服务端,使得系统更加可扩展和可维护。RPC的优势在于它的远程调用机制,可以使得客户端和服务端之间的通信更加高效和简单。
总的来说,ROA和RPC都是用于构建分布式系统的架构风格,但ROA更加注重资源的管理和操作,而RPC更加注重远程调用的过程。在具体的系统设计中,可以根据实际需求选择合适的架构风格。
web地图服务
资源分析与设计
几个步骤
- 理解服务功能
- 梳理必要的资源
- 创建只读资源
- 给资源命名
- 给资源命名的讨论
一些总结
RESTful 服务通过资源(resources)来暴露数据(data)和算法(algorithms)。有关数据的资源常常构成一个层次结构;由很少的资源开始,然后逐渐扩展为具有许多叶结点
要理解“把算法暴露为资源”这一方式。不要从动作(如“在地图上搜索地点”)方面来考虑,而要从该动作的结果方面来考虑(如“地图上符合搜索条件的地点”)
设计资源表述
现在要考虑当客户端请求一个资源时,服务器应返回什么数据(data)及采用什么数据格式(data format)?即,服务已经构思好了,现在要决定为表述(representation)采用什么格式。
- 传达资源状态的表述
- 传达资源状态是表述(representation)的主要用途
- 推进状态
- 表述(representation)的另一个用途是推进状态
- 一个资源的表述应该链接到邻近的资源(这里“邻近”的含义依据上下文而定),比如可能的下个应用状态(application state)。这样做是为了实现连通性(connectedness)——通过跟随链接(following links)从一个资源到另一个资源的能力
- 这样实现的其实还是一个超媒体策略
- 链接到其他状态的表述
- 计算机程序无法自己决定跟随哪个链接,它只按程序员的指示去做。Web服务在表述(representation)里提供链接(links)时,必须同时在这些表述里附上机器可读的 (machine-readable) 信息、指出各个链接是关于什么的。这样,程序员就可以编写客户端程序来读取这些信息,然后确定哪些链接是符合当前目标的
- 这些链接推进的是应用状态(application state)。假如一个资源可以用PUT来修改,或者它在响应POST请求时可以产生新资源,那么它的表述(representation)还应包含推进资源状态(resource state)的链接。该表述应提供必要信息,以说明对POST或PUT请求的要求。
表述格式的选择:XHTML
纯文本和Json的缺点在于它们都不是通常所认为的“超媒体”格式,即没法直接在浏览器中解析使用,如腾讯地图返回的Json格式表述在浏览器中的显示结果仍然是文本;而XML格式的文档中虽然有自描述的结构信息,也没有用于展现的格式信息
为此,我们选择一种折中方案,XHTML,即可扩展超文本标记语言。XHTML表现方式与超文本标记语言(HTML)类似,不过语法上更加严格,另外它增加了扩展能力。标准的XHTML文档兼容HTML,保留了浏览器呈现格式所需的标记,所有浏览器都能够正确显示;同时,XHTML又是可扩展的,每个标签都增加了一个class属性,通过使用class属性,可以传递资源的更多信息
REST安全性和与用户有关的资源设计
REST安全性设计
为什么服务安全性很重要
- 保护数据
- 防止DDos
- 商业影响(避免商业损失)
安全性三方面
①对客户端做身份认证
②对敏感的数据做加密,并且防止篡改
③身份认证之后的访问控制
认证与授权
认证(authentication)要做的,就是把请求跟用户关联起来
授权(authorization)要做的,就是确定某给定用户可做哪些操作
用户身份验证和授权机制
服务器可以用来针对客户端的请求发送质询(challenge),客户端根据质询提供身份验证凭证。质询与应答流程如下:
服务器端向客户端返回401(Unauthorized,未授权)状态码,并在WWW-Authenticate头中添加如何进行验证的信息,其中至少包含有一种质询方式。
客户端可以在请求中添加Authorization字段进行验证,其Value为身份验证的凭证信息。当Web服务客户端发出一个HTTP请求时,它将在报头Authorization字段里附上一些证书(credentials)
在服务收到该请求后,检查证书是否代表某一特定账户(认证),以及该用户是否被允许做它所请求的操作(授权)。若这两个条件都能满足,那么服务将处理该请求,若请求里没有有效的证书,或者该证书未能通过授权,那么服务器将继续发送响应代码401,并在WWW-Authenticate响应报头里指出如何发送有效的证书
OAuth2.0
认证模式是:用户名 + 密码 + 访问令牌 + 刷新令牌
核心思想是:用户使用用户名和密码登录系统后,客户端(用户访问系统的设备)会收到一对令牌,包括访问权限令牌和刷新令牌。
访问令牌用于访问系统中的所有服务。
到期后,系统使用刷新令牌生成一对新的令牌。
JWT
JWT令牌由三部分构成:头、载荷和签名
头:包含加密算法 令牌类型等信息
载荷:包含用户信息 签发时间和过期时间等信息
签名:使用编码后(base64编码)的header和payload再加上我们提供的一个公钥,然后使用header中指定的签名算法进行签名。作用是保证JWT没有被篡改过
优点
- 因为json的通用性,所以JWT是可以进行跨语言支持的
- 因为有了payload部分,所以JWT可以在自身存储一些其他业务逻辑所必要的非敏感信息
- JWT构成非常简单,字节占用很小,非常便于传输
- 不需要在服务端保存会话信息, 所以它易于应用的扩展
- 使用无状态、可扩展的方式处理应用的用户会话。服务端可以通过内嵌的声明信息,很容易地获取用户的会话信息,而不需要去访问用户或会话的数据库。
用户也是一种资源
有了用户概念,应用可以提供更加个性化的服务;另一方面,应用可以根据用户的行为和表现改进应用,拓展业务。
用户画像即用户信息标签化,利用互联网搜集与用户相关的“一切“信息,抽取其中关键词,用简洁的标签来作为用户特征。它可以完美地抽象出一个用户的信息全貌,作为应用大数据的根基,然后用于各类数据挖掘、个性化搜索推荐等工作中
pass
设计可读写的面向资源的服务
面向资源架构的服务设计过程可以归纳为以下六个步骤
- 资源分析与设计
- 规划资源暴露的操作
- 设计服务端资源表述
- 设计客户端资源表述
- 建立资源之间的链接
- 规划服务交互的响应
设计更好的服务——咖啡店的启发
关键在于采用异步方式处理服务
需要解决的问题
通过缓存提升可伸缩性
为防止服务因过载而崩溃,可以使用一个逆向代理(reverse proxy)来缓存并提供那些频繁访问的资源表述。
在架构里增设了Web缓存(逆向代理),再加上有缓存元数据,客户端获取资源时就不会给服务器增添很大负担了
缓存的另一个有利之处是:它屏蔽掉了服务器的间隙性故障,并通过提高资源可用率来帮助灾难恢复
无状态性
所谓有状态指的是要求在多个异步操作的序列间维持事务资源的一定状态,但这就阻碍了消息的自由传递,因为消息只能向特定服务器传递,系统无法横向扩展,这也就等于损害了可伸缩性
异常处理
几种常见的错误处理策略里边有一个共同之处,如果损失不大,就不去追究原因,而是要快速处理,这种效益优先的原则,保证了星巴克经营的利益,因为建立一种纠错方案所花费的代价可能要比就此罢休更加高昂
①重试
当一大组操作(例如一次事务)中的某些操作失败时,我们基本有两种选择:
- 回退已完成的操作
- 重试失败的操作
如果重试有较大的概率能成功,那就可以考虑重试方式。如果失败的原因是违反了业务规则,那重试就不太可能会成功。如果失败的原因是某个外部系统挂了,那重试就有可能会成功。
还记得幂等性吗?这里有一种特殊的重试:幂等接收器重试(retry with Idempotent Receiver)。在这种场景中,我们可以简单地重试所有操作,因为接收器成功之后便会忽略重复的消息
②补偿
补偿是回退所有已完成的操作,让系统回到一致的状态。
例如:网上购物中中某个环节出错了,电商平台通常会采取补救措施(向信用卡退款)或者重试(把丢失的货物重新发送)的策略;在金融交易中,这些“补偿动作”能在交易失败时对已扣款进行退款处理
善用状态码
状态代码是具有丰富语义的确认信息。让服务返回有意义状态代码,并且令客户端懂得如何处理状态代码,这相当于,我们给HTTP简单的请求响应机制增加了一层协调协议,从而提高了分布式系统的健壮性和可靠性
Jersey服务实现
pass
OpenAPI设计
我们需要解决如何把我们的服务描述清楚的问题。也就是说,需要服务开发者能够将API以某种规范的格式公开,而且API 文档能够及时更新以提高工作效率
OpenAPI 规范(OAS)
OpenAPI 规范(OAS)定义了一个标准的、语言无关的 RESTful API 接口规范。
正确定义规范文档后,开发者就可以使用最少的实现逻辑来理解远程服务并与之交互。
OpenAPI 规范(OAS)是一种用于描述 RESTful API 的标准格式,它使用 YAML 或 JSON 格式来定义 API 的接口信息,包括 API 的路径、参数、请求和响应格式等。OAS 的主要目的是为了提供一种统一的标准,使得不同的开发者和开发团队可以更加容易地理解和使用 API,从而提高 API 的可靠性和可用性。
Swagger
Swagger是一款RESTFUL接口的文档在线自动生成+功能测试功能软件。目标是为REST APIs 定义一个标准的,与语言无关的接口,使人和计算机在看不到源码或者看不到文档或者不能通过网络流量检测的情况下能发现和理解各种服务的功能
当服务通过Swagger定义,消费者就能与远程的服务互动通过少量的实现逻辑。类似于低级编程接口,Swagger去掉了调用服务时的很多猜测
微服务架构
微服务架构是一种软件架构风格,它将一个大型的应用程序拆分成多个小型的服务,每个服务都运行在独立的进程中,服务之间通过轻量级的通信机制进行交互。每个服务都专注于完成一个特定的业务功能,可以独立部署、扩展和维护,从而提高了系统的可靠性、可扩展性和灵活性。
在微服务架构中,每个服务都可以使用不同的编程语言、数据库和技术栈,开发团队可以根据自己的需求和技能选择最合适的技术栈,从而提高了团队的生产力和创新性。此外,微服务架构还可以使得应用程序更加容易部署到云环境中,从而实现弹性伸缩和自动化运维。
但是,微服务架构也带来了一些挑战,例如服务之间的通信和协调、服务的数据一致性、服务的安全性和监控等方面都需要更加复杂的处理。因此,在采用微服务架构时需要仔细考虑架构设计和实现细节,以确保系统的可靠性和可维护性。
什么是微服务架构
微服务是由以单一应用程序构成的小服务,自己拥有自己的进程与轻量化处理,服务依业务功能设计,以全自动的方式部署,与其他服务使用HTTP API通信;
微服务是一种架构概念,核心思想在于通过将业务功能和需求分解到各个不同的服务中进行管理,实现对业务整体解耦。围绕业务模式创建应用服务,应用服务可独立地进行开发、迭代、部署,从而可以使项目架构更加清晰明确。
微服务架构的特性与挑战
特性
挑战
Spring Cloud Netflix体系
负载均衡
服务网关——Netflix Zuul
服务调用映射——Open Feign
监控和断路器——Hystrix
什么是降级呢
降级是为了更好的用户体验,当一个方法调用异常时,不是简单等待,而是返回一个友好的提示给客户端,不调用真实服务逻辑,转为调用一个 fallback本地方法,保证服务链条的完整,避免服务雪崩。