服务开发技术期末复习

服务开发技术期末复习

第一章 服务计算:Web新时代的计算

什么是服务

  • 在一个应用软件内部的一种方法、过程、或通讯。这些“服务”或“方法”是旨在满足某些业务需求的应用程序的操作。所谓服务,是区别于系统的,一个或者一组相对较小且独立的功能单元,是用户可以感知最小功能集

Web Service

  • 指那些自我包含的、自我描述的、模块化的,用于供Web网络上其他软件程序使用或访问的应用程序

API(Application Programming Interface)

  • 提供对应用程序或数据库中的服务功能和数据进行编程访问的接口,可以用作开发与人类、其他应用程序或智能设备进行交互的基础

微服务(Microservice)

  • 微服务架构是一种架构概念,旨在通过将功能分解到各个离散的服务中,以实现对解决方案的解耦。
  • 微服务架构主要作用:
    • 将功能分解到离散的各个服务当中,从而降低系统的耦合性,并可以提供更加灵活的服务支持
  • 微服务架构的关键在于强调“微服务”可以在自己的程序中运行,每个微服务完全自治,可以独立进化任意修改与重构;如果其中任何一个服务需要增加某种功能,只需要在特定的某种服务中增加所需功能,而不影响架构整体

第二章 Web服务技术方案:从RPC到REST

Web的技术架构包括了四个基石

  • URI:地址
  • HTTP:传输
  • HyperText:表达(除了HTML外,也可以是带有超链接的XML或JSON)
  • MIME:扩展
    • 本意为多目的Internet邮件扩展,最初目的是为了在发送电子邮件时附加多媒体数据,让邮件客户程序能根据其类型进行处理。
    • 当它被HTTP协议支持之后,它的意义就更为显著了。它使得HTTP传输的不再是仅有普通的文本,而变得丰富多彩起来

URL

HTTP

  • HTTP采用简单的请求/响应模式的消息交换来实现针对某个Web资源的某种操作
  • HTTP动词
    • POST:向服务器提交信息,一般用于创建资源(增)
    • GET:获取服务器端的信息,一般用于浏览资源(查)
    • PUT:用于修改服务器端资源(改)
    • DELETE:用于删除资源(删)

HTTP报文

  • 起始行
    • 请求报文利用起始行表示采用的HTTP方法、请求URI和采用的HTTP版本,而响应报文的起始行在承载着HTTP版本和响应状态码等信息。
  • 报头集合
    • HTTP报文的起始行后面可以包含零个或者多个报头字段。每个报头字段表现为一个键/值对,键和值分别表示报头字段名称和报头字段的值,两者通过冒号(“:”)进行分割。HTTP报文采用一个空行作为报头集合结束的标志
  • 主体内容
    • 代表报头集合结束标志的空行之后就是HTTP报文的主体部分。客户端提交给服务器的数据一般置于请求报头的主体,而响应报头的主体也承载着服务器返回给客户端的数据

REST

  • Representational State Transfer (REST,中文:表述性状态转移)
  • REST视角下,互联网就是一个巨大的状态机;REST风格的应用则是从一个状态迁移到下一个状态的状态转移过程

三种主流的Web服务实现方案

远程过程调用(remote procedure call,RPC)的分布式计算协议

  • 通过XML将调用函数封装,并使用HTTP协议作为传送机制
  • 发出请求的用户端一般都是需要向远端系统要求呼叫的软件
  • XML-RPC通过向装置了这个调用协议的服务器发出HTTP请求
  • 在新的功能不断被引入下,这个标准慢慢演变成为SOAP协议

简单对象访问协议Simple Object Access Protocol,SOAP

  • SOAP是一种通讯规范,采用标准化的、可分析的结构来传递的消息,消息具有标准的格式,并包含一些通讯双方自定义的语义
  • 比如一个查询房价数据的消息参数中标明这是一个针对某房源价格的查询消息,服务器端将返回一个XML 格式的信息,其中包含了查询结果(价格,位置,特点,或者其他信息)

表述性状态转移(Representational State Transfer)

  • REST从资源的角度来观察整个网络,分布在各处的资源由URI确定,而客户端的应用通过HTTP操作来获取资源的表征
  • 互联网上的各种资源就好比数据库中的记录,对于资源的操作最后总是能抽象成为查增改删这四种基本操作;在定义了资源定位的规则后,对资源的操作就可以通过标准HTTP 方法GET、PUT、POST、DELETE实现
  • REST模式的Web 服务将所有Web 系统的服务抽象为资源,并使用标准的HTTP 方法(GET/PUT/POST/DELETE)操作

RESTful服务的优势

  • 使用统一的接口操作资源

    • 由于REST是面向资源的,所以一个Web API旨在实现针对单一资源的操作,针对资源的基本操作唯CRUD而已,故可以为Web API定义标准接口成可能。
    • 所谓的标准接口就是针对不同资源的Web API定义一致性的操作来操作它们
  • RESTful Web服务接口更易于使用

    • RESTful Web服务使用标准的HTTP 方法(GET/PUT/POST/DELETE) 来抽象所有Web 系统的服务能力,而不同的是,SOAP 应用都通过定义自己个性化的接口方法来抽象Web 服务。
    • 标准化的HTTP 操作方法,结合其他的标准化技术,如URI,HTML,XML 等,将会极大提高系统与系统之间整合的互操作能力。更加贴近Web本身的工作方式,也更加自然。
  • 无状态性

    • 所谓“无状态性”,就是对于分布式的应用任意给定的两个服务请求不依赖彼此,处理一次请求所需的全部信息,要么都包含在这个请求里,要么可以从外部获取到(如数据库),服务端本身不存储任何信息。
    • HTTP 协议从本质上说是一种无状态的协议,客户端发出的HTTP 请求之间可以相互隔离,不存在相互的状态依赖
    • 基于HTTP 的RESTful服务请求,继承了其“无状态”特性,可以以非常自然的方式来实现无状态服务请求处理逻辑。
  • 安全操作与幂指相等特性

    • HTTP 的GET、HEAD 请求本质上应该是安全的调用
    • 即:GET、HEAD 调用不会有任何的副作用,不会造成服务器端状态的改变。
    • 对于服务器来说,客户端对某一URI 做n 次的GET、HAED 调用,其状态与没有做调用是一样的,不会发生任何的改变。
    • HTTP 的PUT、DELETE 调用,具有幂指相等特性,或称为幂等性(idempotent)
    • 客户端对某一个URI指代的资源执行1次或者多次的PUT、DELETE操作,其效果与执行一次的调用操作是一样的
  • RESTful Web 服务更容易实现缓存

    • 当客户端第一次发送HTTP GET 请求给服务器并获得内容后,该内容可以被缓存服务器(Cache Server) 缓存。当下一次客户端请求同样的资源时,缓存可以直接给出响应,而不需要再通过请求远程的服务器获得

ROA的协议

简单对象访问协议(SOAP)

  • 提供了一个标准的封装结构,用来在各种不同的互联网协议(如SMTP、HTTP和FTP)上传输XML文档。通过使用这样的标准消息格式,异构的中间件系统可以实现互操作

Web服务描述语言(WSDL)

  • 描述了接口,即Web服务支持的一系列标准格式的操作。它标准化了操作的输入和输出参数的表示以及服务的协议绑定,消息在线传输的方式。使用WSDL,不同的客户端可以自动理解如何与Web服务交互

通用描述、发现和集成

  • 提供了一种通过搜索名称、标识符、类别或Web服务实现的规范来广告和发现Web服务的全局注册表

REST

第三章 资源和表述

资源

  • 任何寄宿于Web可供操作的“事物”均可视为资源,就其本质而言,任何足够重要并被引用的事物都可以是资源。

资源的表征

  • 资源可以具有多种表现形式,这种资源的呈现形式,称作资源的表征

资源需要有唯一的标识符

  • 资源请求者和资源拥有者只有在对事物的命名上达成一致以后才能针对这个事物实现相互通信。
  • 因此,每个资源必须拥有自己的唯一标识,互联网中使用URI 来唯一标记一个资源,包含了URL和URN
  • URL(Uniform Resource Location):统一资源定位符,侧重于 “定位” 二字。
  • URN(Uniform Resource Name):统一资源名称,侧重于 “命名”二字。

为什么要对资源表述

  • 从资源请求者的角度看,它并不关心资源是什么,因为它从来看不到资源,它看到的永远只是资源的URL和表述(Representation)。
  • 客户端应用与服务端的交互,是通过资源的表述来间接完成的,这体现了一些非常好的设计原则:松耦合与前后端分离
  • 通过资源的表述来间接完成交互,实际上就是隔离了客户端与服务端、前端与后端,使得请求服务的一方的操作不会直接影响到服务提供者,而服务提供者也可以安全地分享自己的资源

超文本(HyperText)

  • 是用超链接的方法,将各种不同空间的文字信息组织在一起的网状文本,其中的文字包含有可以链接到其他文档的地址,以实现从当前阅读位置直接切换到超文本链接所指向的文本继续访问。

超媒体(HyperMedia)

  • 是超级媒体的缩写。超媒体是一种采用非线性网状结构对块状多媒体信息(包括文本、图像、视频等)进行组织和管理的技术。
  • 超媒体在本质上和超文本是一样的,只不过超文本技术在诞生的初期管理的对象是纯文本,所以叫做超文本。

超媒体策略:

  • 超媒体可以帮助服务器实现与客户端的对话:服务器在发给客户端的文本中附加超链接,以告知客户端如何进一步向服务器发起请求。
  • 服务提供者可以在发给客户端的文本中附加广告信息的超链接,引导用户新的消费行为。
  • 可以用超媒体写一个服务器提供的功能菜单,客户端可以从中自由选择,目前大多数应用都是这样做的

HATEOAS

  • 超文本作为应用程序状态的引擎(Hypertext as the Engine of Application State,HATEOAS)是Rest的一项重要原则
    HATEOAS例子

HTTP协议语义

  • 尽管任何事物都可以成为一个资源,但是客户端并不能随心所欲地对资源进行任意的操作。所能进行的操作是有规定的。在一个RESTful系统里,客户端和服务器端只能通过相互发送遵循预定义协议的消息来进行交互
  • 在web API的世界里,这个协议就是HTTP。API客户端可以通过发送一些不同类型的HTTP消息与API进行交互
  • 向一个“博客日志”发送的GET请求和向一个“股票代码”发送的GET请求是类似的。这两个请求拥有相同的协议语义,但是却有完全不同的应用语义(application semantic)
  • 无法仅仅通过使用HTTP来满足这样的语义要求,因为HTTP协议并没有定义任何应用语义。但是应用语义必须和HTTP的协议语义保持一致。

GET方法

  • GET是被定义为安全的HTTP方法。它仅仅是对信息的一次请求。向服务资源发送一条GET请求对资源的影响应该和没有发送GET请求一样——也就是,没有任何影响。
  • GET请求中最常见的响应码是200 (OK)。此外像300 (Moved Permanently)这样的重定向码也比较常见。

DELETE

  • DELETE很明显不是一个安全的方法。发送一个DELETE请求的效果不同于未发送DELETE请求。但是DELETE方法有另外一个很有用的属性:它是幂等的(idempotent)
  • 一旦你删除了一个资源,这个资源就消失了。资源状态也就永久性地改变了。你可以再次发送一条DELETE请求,这时,你可能会收到一个404错误,但是资源状态和你第一发的送发ELETE请求之后的状态是一致的。资源还是不存在的。这就是幂等性。发送两次请求对资源状态的影响和发送一次请求的影响是一样的
  • 如果一个DELETE请求发送成功了,收到的状态码可能是204(No Content,也就是,“删除成功,我没有其他关于这个资源的信息描述了),也可能是200 (OK,也就是“删除成功,这里是关于它的一条消息”)或者202 (Accepted,也就是“我稍后将删除这个资源”)
  • 幂等性:
    • 幂等是一个很有用的特性,因为互联网不是一个可靠的网络。
    • 假设你发送了一个DELETE请求,然后你的连接超时了。由于你并没有收到响应信息,所以你无法知道前面的DELETE请求是否顺利完成。你只要再次发送一条DELETE请求并不断重试直到收到响应信息就可以了。
    • 执行两次DELETE请求并不比只执行一次造成更多的影响。
    • HTTP DELETE方法就相当于用零乘以一个资源。
    • 乘以1是一个安全的运算,HTTP GET也是一个安全的方法。你可以将一个数值不停地乘以1,数值不会产生任何变化。每个安全的运算都是幂等的。

POST:POST-to-Append

  • 向某个资源发送一条POST请求用以在该资源的下一级中创送一个新的资源。
  • 当客户端发送一个POST-to-append请求的时候,它会在请求的实体消息体中添加所希望创建的资源的表述信息并发送给服务器
  • 常见的响应码:
    • 201(Created)它用于告知客户端一个新的资源已经创建成功。
    • 202(Accepted)这表示服务器打算按照提供的表述信息来创建一个资源,但是现在还没有真正创建完成
  • 既不安全也不幂等

POST:Overloaded POST

  • 大部分浏览器只支持GET/POST方法,这使得我们无法完美的实现REST。对于这样的情况,大致有两种解决方法:
    • 一种是在表单里加入一个_method之类名字的隐藏字段,用于表示真正的方法
    • 另一种是使用X-HTTP-METHOD-OVERRIDE头信息来重载POST
  • POST不仅仅被用于创建新的资源。在我们用浏览器上网的时候,HTTP POST也被用于传输任何形式的变化。
    • 它将PUT、DELETE、PATCH、LINK和UNLINK所有的方法混合成一个方法
  • 将POST这种“任意而为(whatever)”用法称为重载的(overloaded) POST
  • 因为一个重载的POST请求没有协议语义,你只能在应用语义的层面上来理解它
  • 不安全也不幂等(在事实上可能安全,在HTTP上是不安全的)

PUT

  • PUT请求是用于修改资源状态的请求。客户端一般会通过GET请求获取表述,然后对其进行修改,最后再将修改后的资源表述作为PUT请求的负载数据(payload)发送回去。
  • 返回200(OK)或204(No Content)
  • 幂等,如果你发送10次同样的PUT请求,请求的结果和你只发1次请求的结果是一样的
  • 如果客户端知道新资源的URL的话,它同样能够使用PUT来新建一个资源。
  • 即便我们用PUT来创建一个新的资源,PUT也还是一个幂等的操作。
  • 如果我发送5次PUT请求,这并不会相应生成5条具有同样内容的微博(而5次POST请求会生成5条相同的微博)

PUT VS POST

  • 区别在于POST是作用在一个集合资源之上的(/articles),而PUT操作是作用在一个具体资源之上的(/articles/123)
  • 如果URL可以在客户端确定,那么就使用PUT
  • 如果是在服务端确定,那么就使用POST
  • 比如说很多资源使用数据库自增主键作为标识信息而创建的资源的标识信息到底是什么只能由服务端提供,这个时候就必须使用POST

PATCH

  • 表述的信息量可能非常大。“修改表述,然后通过PUT方法提交”是一个简单的规则
  • 但是如果你只是想修改资源状态中的很小的一部分,这就可能造成极大的浪费。
  • 此外,PUT规则还可能导致与其他修改同样文档的用户发生意外的修改冲突。
  • 如果你可以仅仅向服务器发送你想要修改的那一部分数据文档,那PATCH方法就提供了这样的功能来允许你这么做
  • 和将完整的表述信息通过PUT方法发送出去不同,你可以建立一个特别的“diff‘’表述,并将它作为PATCH请求的负载数据发送给服务器
  • 不安全也不保证幂等
  • 一个PATCH 请求有可能结果是等幂的,这种情况下,如果你不小心对同一个文档应用了两次patch,你可能会在第二次收到一个错误信息。但这并没有定义在相关标准中。
  • 和GET一样安全,可理解为轻量版GET
  • 服务器和GET一样处理HEAD,但不返回消息体,只需发送状态码和报头
  • (待定)HEAD代替GET不会节约时间,因为服务器还是需要生成所有HTTP报头,但能节省带宽

OPTION

  • 一个OPTIONS请求的返回结果包含一个HTTP Allow报头,这个报头展示了这个资源所支持的所有的HTTP方法。

响应码

1xx相关信息(不常用)

状态码 内容 作用
100 Continue 继续。客户端应继续其请求
101 Switching Protocols 切换协议。服务器根据客户端的请求切换协议。智能切换到更高的协议,例如,切换到HTTP的新版本协议

2xx操作成功

状态码 内容 作用
200 OK 请求成功。一般用于GET与POST请求
201 Created 已创建。成功请求并创建新的资源
202 Accepted 已接受。已经接受请求,但未处理完成
203 Non-Authoritative Information 非授权信息。请求成功。但返回的meta信息不在原始的服务器,而是一个副本
204 No Content 无内容。服务器成功处理,但未返回内容。在未更新网页的情况下,可确保浏览器继续显示当前文档
205 Reset Content 重置内容。服务器处理成功,用户终端(例如:浏览器)应重置文档视图。可通过此返回码清除浏览器的表单域
206 Partial Content 部分内容。服务器成功处理了部分GET请求

3xx重定向(不常用)

状态码 内容 作用
300 Multiple Choices 多种选择。请求的资源可包括多个位置,相应可返回一个资源特征与地址的列表用于用户终端(例如:浏览器)选择
301 Moved Permanently 永久移动。请求的资源已被永久的移动到新的URI,返回信息会包括新的URI,浏览器会自动定向到新URI。今后任何新的请求都应使用新的URI代替
302 Found 临时移动。与301类似。但资源只是临时被移动。客户端应继续使用原有URI
303 See Other 查看其它地址。与301类似。使用GET和POST请求查看
304 Not Modified 未修改。所请求的资源未修改,服务器返回此状态码时,不会返回任何资源。客户端通常会缓存访问过的资源,通过提供一个头信息指出客户端希望只返回在指定日期之后修改的资源
305 Use Proxy 使用代理。所请求的资源必须通过代理访问
306 Unused 已经废弃的HTTP状态码
307 Temporary Redirect 临时重定向。与302类似。使用GET请求重定向

4xx客户端错误

状态码 内容 作用
400 Bad Request 客户端请求的语法错误,服务器无法理解
401 Unauthorized 请求要求用户的身份认证
402 Payment Required 保留,将来使用
403 Forbidden 服务器理解请求客户端的请求,但是拒绝执行此请求
404 Not Found 服务器无法根据客户端的请求找到资源(网页)。通过此代码,网站设计人员可设置“您所请求的资源无法找到”的个性页面
405 Method Not Allowed 客户端请求中的方法被禁止
406 Not Acceptable 服务器无法根据客户端请求的内容特性完成请求
407 Proxy Authentication Required 请求要求代理的身份认证,与401类似,但请求者应当使用代理进行授权
408 Request Time-out 服务器等待客户端发送的请求时间过长,超时
409 Conflict 服务器完成客户端的PUT请求时可能返回此代码,服务器处理请求时发生了冲突
410 Gone 客户端请求的资源已经不存在。410不同于404,如果资源以前有现在被永久删除可使用410代码,网站设计人员可通过301代码指定资源的新位置
411 Length Required 服务器无法处理客户端发送的不带Content-Length的请求信息
412 Precondition Failed 客户端请求信息的先决条件错误
413 Request Entity Too Large 由于请求的实体过大,服务器无法处理,因此拒绝请求。为防止客户端的连续请求,服务器可能会包含一个Retry-After的响应信息
414 Request-URI Too Large 请求的URI过长(URI通常为网址),服务器无法处理
415 Unsupported Media Type 服务器无法处理请求附带的媒体格式
416 Requested range not satisfiable 客户端请求的范围无效
417 Expectation Failed 服务器无法满足Expect的请求头信息

5xx服务器错误

状态码 内容 作用
500 Internal Server Error 服务器内部错误,无法完成请求
501 Not Implemented 服务器不支持请求的功能,无法完成请求
502 Bad Gateway 充当网关或代理的服务器,从远端服务器接收到了一个无效的请求
503 Service Unavailable 由于超载或系统维护,服务器暂时无法处理客户端的请求。延时长度可包含在服务器的Retry-After头信息中
504 Gateway Time-out 充当网关或代理的服务器,未及时从远端服务器获取请求
505 HTTP Version not supported 服务器不支持请求的HTTP协议版本,无法完成处理

第五章 领域驱动的服务设计

领域建模产出物

  • 领域模型:包含领域对象、属性、关系、行为、边界范围等各个方面,用于描述业务的本质
  • 用例图:用于明确系统的功能
  • 数据模型:描述系统的数据结构和关系,包括实体关系模型、关系数据库模型等
  • 状态图:用于描述系统各个状态及其转移条件
  • 活动图:用于描述系统流程中的各个活动及其关系
  • 序列图:描述系统中各个对象之间的交互过程和消息传递序列
  • 架构模型:包含系统的物理和逻辑结构,包括组件、模块、接口等

领域驱动设计(DDD)

  • 针对一个领域内各个业务需求进行建模,同时提供了战略和战术上的建模方法和工具。
  • 模型驱动的思想:通过建立领域模型来描述领域中的核心问题

DDD主要任务

  • 一是如何发现系统中的聚合(Aggregate)
    • 所谓聚合是一组相关的领域对象(或者称为实体),是由业务和逻辑紧密关联的实体和值对象组合而成的,值对象可以理解为实际的Entity对象的一个属性的结合,附属在一个实际的实体对象上面
  • 二是如何划分限界上下文(Bounded Context)
    • 系统的上下文(context)指的是目标系统、与之交互的用户和外部系统

第六章 设计只读的资源服务

ROA vs RPC

  • 面向对象程序的标准设计方法是把系统分解为一个个功能部件——即其中的名词(nouns)。
    • 一个对象(object)是(is)某个事物(如“读者”、“栏目”、“报道”、“评论”等)。
    • 每个名词都有自己的类和自己的方法(用以与其他名词交互)
  • 与此形成对比的是,RPC式架构的设计方法是把系统分解为一个个动作,即其中的动词(verbs)。
    • 一个过程(procedure)做(does)某些操作(比如“订阅”、“阅读”、“作评论”等),在面向RPC的分析中,它会被视为将被客户端调用的动作(action)

ROA

  • 一个资源(resource)是(is)某个事物,所以适合用面向对象的方法来设计资源
  • 编程语言里的一个类(class)可以暴露无数个方法(methods),并给这些方法取任意名(name)
  • 但是,一个资源只暴露一个统一接口,最多支持六种HTTP方法,这些方法只允许创建(PUT或POST)、修改(PUT)、读取(GET)和删除(DELETE)这些最基本的操作
    • 如果需要,也可以通过重载(overload) POST来扩展该接口,把一个资源变成一个小型RPC式消息处理器。不过一般不鼓励这样
  • 统一接口(uniform interface)意味着,在面向对象设计里被视为动词(verb)的事物,在面向资源的设计里必须被视为对象(object)

资源分析与设计

  • 理解服务功能
  • 梳理所拥有的资源
  • 创建只读资源
    • 设定资源入口:必须有一个所有可用资源的最上层目录,例如地图网站的首页,需要将这个资源入口的URL公布出去,作为获取其他资源的入口。
    • 根据服务确定需要暴露的资源:一个服务可以暴露很多对象,每一种都有自己的资源集合。比如我们要开发的地图服务如果要提供可视化的地图展现,就需要提供地图图片;如果服务提供地点的精确位置信息,就需要知道地点对应经纬度(这些数据可能存储在关系数据库中)。
    • 作为查询结果的集合资源:地图服务通过资源来最终暴露数据和产生数据的算法,比如地图上的路径规划,实际上是一个有条件约束的最短路径算法,执行以后会得到一个地点序列,构成路径。
  • 给资源命名
    • 资源命名需要精巧地设计,确保资源命名规则的合理、规范、一致,更重要的是要易于扩展,因为很多情况下(甚至可以说绝大多数情况下),资源名字都是由程序自动生成的。
    • 针对资源特点和设计经验,我们的URI设计基于三条基本原则:
      • 用路径变量(path variables)来表达层次结构(hierarchy),如: /parent/child
      • 在路径变量里用标点符号表达多个信息,如经纬度:/24.9195,17.821
      • 用查询变量(query variables)来表达算法的输入,例如:/search?q=j ellyfish&start=20

设计资源表述

传达资源状态的表述

  • 传达资源状态是表述(representation)的主要用途
  • “资源状态”就是有关资源的任何信息。在我们的服务里,资源状态将回答类似这样的问题:
    • 某一个地点的地图是什么样的?
    • 某个地点的经纬度是多少?
    • 附近哪里有餐厅,它们都叫什么名称?等等
  • 不同资源的表述传达的是不同的状态

推进状态

  • 表述(representation)的另一个用途是推进状态
  • 一个资源的表述应该链接到邻近的资源(这里“邻近”的含义依据上下文而定),比如可能的下个应用状态(application state)。这样做是为了实现连通性(connectedness)——通过跟随链接(following links)从一个资源到另一个资源的能力
  • 网站就是这样工作的:
    • 你在上网时不是接连输入URls,相反,你先通过输入URI进入网站的主页,然后通过跟随链接来浏览网页。一个网页(该网站的一个“状态”)包含指向其他相关网页(邻近“状态”)的链接

表述格式的选择

  • 纯文本: http://maps.example.com/China/Beijing
  • 纯文本比较简单,但它需要专用的解析器。一般来说,结构化数据格式要比纯文本好,尤其当表述比较复杂时,可以用结构化的文本格式,它保留了纯文本简单的优点,同时增加了一些结构信息,比如:[{url="http://maps.example.com/China/Beijing, description="Beijing,a city of China"}]
  • 纯文本和Json的缺点:它们都不是通常所认为的“超媒体”格式,即没法直接在浏览器中解析使用,如图所示腾讯地图返回的Json格式表述在浏览器中的显示结果仍然是文本;而XML格式的文档中虽然有自描述的结构信息,也没有用于展现的格式信息。
    腾讯地图
  • 折中:XHTML,可扩展超文本标记语言
  • 原因:标准的XHTML文档兼容HTML,保留了浏览器呈现格式所需的标记,所有浏览器都能够正确显示;同时,XHTML又是可扩展的,每个标签都增加了一个class属性,通过使用class属性,可以传递资源的更多信息,比如:
    1
    2
    3
    4
    5
    <ul class="Map">
    <li><a href="/China">China</a></li>
    <li><a href="/France">France</a></li>
    ...
    </ul>
  • 这种为XHTML标签增加语义的方式又称为微格式,微格式是一套建立在现有的、广泛采用的标准之上的、简单而开放的数据格式。
  • 这样引入语义信息对浏览器等所有现存的Web技术冲击最小。
  • 下面的一段文字通过class定义了明确的结构语义,从”adr”、”street-address”、”tel”、”email”等这些属性名字看,这里表达的是一个地址信息,这些内容可以被获得这个表述的程序解析使用。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    <div class="vcard">
    <div class="fn org">Wikimedia Foundation Inc.</div>
    <div class="adr">
    <div class="street-address">200 2nd Ave. South #358</div>
    <div>
    <span class="locality">St. Petersburg</span>,
    <span class="region">FL</span>
    <span class="postal-code">33701-4313</span> </div>
    <div class="country-name">USA</div></div>
  • 这段文字嵌入HTML中,在浏览器中,会显示一段有格式的资源信息,可以尝试一下,去掉文字中所有的class字段,显示的内容是一样的
  • XHTML微格式实际是为现有HTML元素添加元数据和其他属性,通过XML把结构语义嵌入到HTML增强语义,兼顾人机可读性

规划服务交互的响应

  • 服务的设计者需要有非常清晰的思路:在设计时想清楚在服务双方的往来交互中会发生哪些典型的事件?
  • 用户向一个URI发出GET请求,服务器返回正确的响应代码(比如200)、一些HTTP报头(HTTP headers)及一个实体主体(表述)
  • 这里最重要的问题是:客户端的请求和服务器的响应里分别应包含哪些HTTP报头,以及,确保服务器能对客户端的请求作出正确的响应
  • HTTP响应报头包含很多信息
    • Content -Type是最重要的HTTP响应报头,它告诉客户端表述的媒体类型(media type of the representation),对于地图和搜索结果来说,application/xhtml+xml,对于地图图像来说,image/png

条件HTTP GET

  • 有些资源不会变化但会被多次请求,大部分时候,客户端对一个资源的第二次(及以后多次)HTTP请求完全可以重用上一次请求时获得的表述。此时服务器返回一个表述时,服务器应该为Last-Modified报头设置一个时间值,表示数据最后更新的时间。当客户端再次请求时,在If-Modified-Since报头里提供那个最后更新时间
  • 加入资源发生了变化,服务器返回200(OK),并在实体主体里提供最新的表述————与一次正常HTTP请求一样
  • 若数据没有变化,服务器将返回304(Not Modified),并省去实体主体,这样客户端就直到可以重用已缓存的表述了
  • 优点:客户端和服务器双方均节省了时间与带宽

只读的面向资源服务的设计过程:

  • 资源分析与设计
  • 设计资源表述
  • 把资源互相联系起来
  • 规划服务交互的响应

第七章 Restful服务的安全性

如何保证

  • 对客户端做身份认证
  • 对敏感的数据做加密,并且防止篡改
    • 常见做法:部署SSL(Secure Sockets Layer 安全套接层)基础设施(即HTTPS),敏感数据的传输全部基于SSL;或者仅对部分敏感数据加密,并加入某种随机数作为加密盐,以防数据被篡改
  • 身份认证之后的访问控制
    • 主要是由应用来控制。通常应该实现某种基于角色+用户组的授权机制,即基于角色的访问控制(Role-Based Access Control,RBAC)

身份验证和授权方法

Basic认证

  • 认证模式:用户名+密码+Base64
  • 每次请求都带着用户名和密码

摘要(Digest)认证

  • 认证模式:md5加密=摘要
  • 过程:
    • 服务器产生一个随机数nonce,放在在WWW-Authenticate响应头,与服务器支持的认证算法列表,认证的域realm等一起发送给客户端。
    • 客户端输入用户名和密码,并计算出密码和其他需要加密的数据的摘要,并放在Authorization的请求头中发送给服务器
    • 服务从请求信息中提取出摘要,与自身保存的用户名密码计算所得摘要进行比对
    • 如果验证通过,则返回:200 OK
  • 随机数作用:能够防止完全相同的请求的重放

OAuth2.0

  • Basic认证和摘要认证都是单次认证,每次用户发起请求都需要重复认证
  • 认证模式:用户名+密码+访问令牌+刷新令牌
  • 核心思想:用户使用用户名和密码登录系统后,客户端(用户访问系统的设备)会收到一对令牌,包括访问权限令牌和刷新令牌。
  • 访问令牌用于访问系统中的所有服务。
  • 到期后,系统使用刷新令牌生成一对新的令牌。

Bearer Token

  • Oauth2.0规范的组成部分

JWT

  • 规定了一种JSON格式的Token实现方式
  • 包含:头、荷载和签名
    • 头:包含加密算法令牌类型等信息
    • 载荷:包含用户信息签发时间和过期时间等信息
    • 签名:根据头、载荷及密钥加密得到的哈希串,默认使用HS256 (HmacSha1 256)。作用是保证JWT没有被篡改

Session vs JWT

传统的session认证

  • http协议本身是一种无状态的协议,为了让应用能识别是哪个用户发出的请求,只能在服务器存储一份用户登录的信息,这份登录信息会在响应时传递给浏览器,告诉其保存为cookie,以便下次请求时发送给应用,这样应用就能识别请求来自哪个用户了,这就是传统的基于session认证

基于token的鉴权机制

  • 基于token的鉴权机制不需要在服务端去保留用户的认证信息或者会话信息。这就意味着应用不需要去考虑用户在哪一台服务器登录了,这就为应用的扩展提供了便利

第九章 星巴克案例

案例的意义

咖啡店案例意义

需要解决的问题

通过缓存提升可伸缩性

  • 作为经营者,其实很不喜欢业务波动,不希望给服务增添负担、或者徒然增加业务流量。
  • 为防止服务因过载而崩溃,可以使用一个逆向代理(reverse proxy)来缓存并提供那些频繁访问的资源表述
  • 在架构里增设了Web缓存(逆向代理),再加上有缓存元数据,客户端获取资源时就不会给服务器增添很大负担了

无状态性

  • 所谓有状态指的是要求在多个异步操作的序列间维持事务资源的一定状态,但这就阻碍了消息的自由传递,因为消息只能向特定服务器传递,系统无法横向扩展,这也就等于损害了可伸缩性
    无状态性

异常处理

  • 重试
  • 补偿:补偿是回退所有已完成的操作,让系统回到一致的状态。例如:退款/重新发货

善用状态码

第十章 RESTful服务开发(Jersey)

服务设计步骤

  • 资源分析与设计
  • 客户端表述的设计
  • 服务端表述的设计
  • 暴露资源可执行接口
  • 多种资源整合到一起
  • 规划服务交互的响应

服务开发步骤

  • 设置开发环境,导入必要的框架
  • 开发环境中创建一个web工程
  • 描述服务接口
  • 实现服务功能

Jersey常用注解

  • @Path,标注资源类或者方法的相对路径;
  • @GET,@PUT,@POST,@DELETE标注方法是HTTP请求的类型;
  • @Produces,标注返回的MIME媒体类型;
  • @Consumes,标注可接受请求的MIME媒体类型;
  • @PathParam,@QueryParam,@HeaderParam,@CookieParam,@MatrixParam,@FormParam标注方法的参数分别来自于HTTP请求的不同位置。
    • 例如@PathParam来自于URL的路径,@QueryParam来自于URL的查询参数,
    • @HeaderParam来自于HTTP请求头信息,@CookieParam来自于HTTP请求的Cookie

@Path

  • 定义资源的访问路径,注解的值是一个相对的URI路径。client通过这个路径访问资源。比如:@Path(“user”)

为资源方法指定符(resource method designator)

  • 与HTTP规范中定义的方法一致
  • @GET, @PUT, @POST, @DELETE, @HEAD

@Produces

  • 可以用于注解类或者注解方法,指定返回给客户端的MIME媒体类型,即服务器端产生的响应实体的媒体类型
  • 方法的@Produces注释将会覆盖类的注释。资源按照指定数据格式返回,可以是XML、Json等媒体类型。
  • 可取的值有:
    • @Produces(MediaType.TEXT_PLAIN)
    • @Produces(MediaType.APPLICATION_JSON)
    • @Produces(MediaType.APPLICATION_XML)
  • 服务端可以指定优先回复某一种类型,如下qs=0.9指定XML格式优先级更高。
    1
    2
    3
    4
    @GET
    @Produces({"application/xml; qs=0.9", "application/json"})
    public String doGetAsXmlOrJson() {
    ...}

@Consumes

  • 指定可以接受的客户端请求的MIME媒体类型。只有符合这个参数设置的请求才能访问到这个资源。
  • 例如:@Consumes(“application/x-www-form-urlencoded”)接受表单数据;@Consumes(“text/plain”)接受纯文本数据

参数注解

@PathParam

  • 用于提取路径中的参数
    1
    2
    3
    4
    5
    6
    @GET
    @Path("{username} ")
    @Produces(MediaType.APPLICATION_JSON)
    public User getUser(@PathParam("username") String userName) {
    //...
    }

@QueryParam

  • 用于提取查询参数。获取请求中的查询参数,这些参数在URL中跟在“?”符号后面。
    1
    2
    3
    4
    5
    @GET
    @Path("/user")
    @Produces("text/plain")
    public User getUser(@QueryParam("name") String name, @QueryParam("age") int age)
    { ...}

@DefaultValue

  • 默认参数值。可指定参数的缺省值:
    1
    2
    3
    4
    @GET
    @Path("/user")
    @Produces("text/plain")
    public User getUser(@QueryParam("name") String name, @DefaultValue("26") @QueryParam("age") int age) { ...}

@MatrixParam

  • 矩阵参数,提取URL路径中嵌入的任意个数个name 和value的键值对
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    @Path("/books")
    public class BookService {
    @GET
    @Path("{author}")
    public Response getBooks(@PathParam("author ") String author,@MatrixParam("bookname") String bookname,@MatrixParam("publisher") String publisher) {
    return Response
    .status(200)
    .entity("getBooks is called, author : " + author
    + ", bookname : " + bookname + ", publisher : " + publisher)
    .build();
    }
    }

@HeaderParam

  • 从请求的头部提取Header

@CookieParam

  • 提取cookie

@Context

  • 标注上下文
  • 大型的服务器中由于参数的多变,参数结构的调整很容易遇到问题,可使用@Context来注解上下文,获取与请求或响应相关的上下文Java类型
  • 注入ResourceInfo、UriInfo、HttpHeaders、ServletConfig、ServletContext、HttpServletRequest、HttpServletResponse、SecurityContext等对象
  • 配合使用HTTP头上下文,可获取header和cookie的所有值:
    1
    2
    3
    4
    5
    @GET
    public String get(@Context HttpHeaders hh) {
    MultivaluedMap<String, String> headerParams = hh.getRequestHeaders();
    Map<String, Cookie>cookieParams = hh.getCookies();
    }

@FormParam

  • 从POST请求的表单中获取数据;用于提取请求中媒体类型
  • 为”application/x-www-form-urlencoded” 的参数,根据相应表单类型提取其中的参数。
    1
    2
    3
    4
    5
    @POST
    @Consumes("application/x-www-form-urlencoded")
    public void post(@FormParam("name") String name) {
    //
    }

@BeanParam

  • 用于从请求的各部分中提取参数,并注入到对应的Bean中

第十二章 OpenAPI规范与设计

OpenAPI规范的作用

  • 定义了一个标准的、语言无关的RESTful API 接口规范
  • 正确定义规范文档后,开发者就可以使用最少的实现逻辑来理解远程服务并与之交互
  • 此外,借助于文档生成工具,可以使用OpenAPI规范来生成API 文档,代码生成工具可以生成各种编程语言下的服务端和客户端代码,测试代码和其他用例

第十三章 微服务架构

微服务架构

  • 微服务是由以单一应用程序构成的小服务,自己拥有自己的进程与轻量化处理,服务依业务功能设计,以全自动的方式部署,与其他服务使用HTTP API通信;

微服务 vs 单体系统

微服务

  • 微服务架构将单个服务对应到单个业务功能,方便理解、开发和维护。
  • 其次,服务独立部署,可以根据每个服务的请求量来部署满足需求的规模;在需要添加新功能的时候,可以独立进行开发,随时更新、部署,不会影响其他线上的服务。

单体系统

  • 单体应用将系统所有的逻辑都放到一起,所有的功能模块都整合在一起,逻辑复杂,代码臃肿,任何一个模块出现异常,都可能会导致应用服务器宕机;一旦系统需要扩展,不管是功能扩展还是性能扩展,对于单体系统难度都很大,尤其是性能扩展,只能把整个单体应用复制到多态服务器上。

微服务的特性

  • 服务组件化
  • 按业务组织团队
  • 做产品的态度
  • 轻量化通信机制
  • 去中心化治理
  • 去中心化管理数据
  • 基础设施自动化
  • 容错设计
  • 演进式设计

微服务面临的挑战

服务治理

  • 将单体应用拆分为服务之后,需要对服务进行高效的管理,才能保证服务正常的运行,系统也才能为用户提供稳定的服务。

服务通信

  • 微服务中不再像单体应用中一样,可以直接进行调用。服务之间需要进行网络通信。需要考虑服务之间如何高效地进行通信。

负载均衡

  • 负载均衡是微服务架构中必须使用的技术,通过负载均衡才可以实现系统的高可用、服务集群化等优化性能。

服务网关

  • 每个微服务在通信中都需要实现认证、权限控制和日志等通用网关功能,且通信协议多样,导致客户端复杂笨重;需要引入服务网关支持。

服务开发技术期末复习
https://sdueryrg.github.io/2025/06/03/服务开发技术期末复习/
作者
yrg
发布于
2025年6月3日
许可协议