0%

Restful API理论

什么是REST

  • Rest就是Representational State Transfer(状态表述转换)的简写
  • 它描述了Webyingyong到底是怎么样设计才算是优良的,这里定义了以下三点:
    1. 一组网页的网络
    2. 在这些网页上,用户可以通过点击链接来前进(状态转换)
    3. 点击链接的结果是下一个网页(表示程序的下一个状态)被传输到用户那里,并渲染好给用户。
  • Rest是一种架构风格,而不是规范或者标准,它需要使用一些规范、协议或者标准来实现这种架构风格,但它又与协议无关。Json和Http并不是Rest强制使用的,只是比较多的人用Json和Http来实现Rest架构风格。

Rest的优点

  1. 性能:由于Rest在通讯上是比较简单和高效的。
  2. 组件交互的可扩展性:一般分布式都有这个优点。
  3. 组件的可修改性:关注点分离,可以使各个组件以最小的成本和风险进行修改(各自进化)。
  4. 可移植性:Rest跟平台或技术都无关,任何平台都可以使用Rest风格来构建应用。
  5. 可靠性:Rest提出的是一种无状态约束,这种约束就可以在系统发生故障后轻松地恢复系统。像传统的Mvc就是有状态的,即Cookie和Session
  6. 可视性

Rest的约束

  1. 客户端-服务器(前后端分离)
  2. 无状态:服务器无须记住客户端的状态,即客户端会记录自己的状态
  3. 统一的资源接口/界面
    1. 资源的标识(URI)
    2. 通过表述来对资源进行操纵
    3. 带有自我描述信息
    4. 超媒体作为应用程序状态的引擎(HATEOAS)
  4. 多层系统 :系统中的每一层只知道自己的上一层或下一层。
  5. 可缓存:缓存响应数据,可以减少客户端感知资源的响应时间,提高可用性和可靠性,客户端可以选择从缓存或数据源获取数据。
  6. 按需编码(可选约束)

Richardson成熟度模型

  • Level0,POX沼泽:只使用了Http协议
  • Level1,资源:每个资源都映射到不同的URI,但Http动词没有用对
  • Level2,动词:正确地使用了Http动词
  • Level3,超媒体:支持HATEOAS
  • 当WebApi达到Level3后,才有可能是一个Restful Api。

资源命名

使用名词,而不是动词

  • 比如:我想获取系统中所有地用户,错误地URI:api/getusers

  • 在Rest中,获取是一个动词,应该由Http动词来表示,所以正确的URI是:GET api/users

要体现资源的结构/关系

  • 假如后端Api由若干种资源,而用户这个资源于其他的资源并没有直接的关系,这样的话获取用户资源的URI应该是api/users,而不是api/products/users,因为user和product没有直接的关系。
  • 通过id获取单个用户的URI应该是:api/users/{userId}
  • 这样写的好处是可以让Api具有很好的可预测性和一致性。

例子:获取公司下面的员工信息和某一个员工的信息

URI分别是:

获取公司下面的员工信息:api/companies/{companyId}/employees

获取公司下面某一个员工的信息:

api/companies/{companyId}/employees/{employeeId}

这样就能体现公司资源和员工资源的关系

自定义查询

  • 有一些操作并不是针对于资源的,而是对资源的获取加以条件的,例如:排序、过滤、分页等,对于这些条件查询一般都是用查询字符串(query string)来表示

例子:获取所有的用户信息,并按照年龄从小到大进行排列

正确的做法是:api/users?orderby=age

例外

  • 有一些需求总是无法满足Restful的约束,比如:想获取系统里所有用户的数量。
  • 妥协的做法:api/users/total_amount_of_user

Http方法

  • 不同的动作可以作用于相同的资源URI,下面使用公司的资源来表示各个Http方法是如何使用的

POST:添加一个公司信息

Snipaste_2020-09-20_16-05-05

GET

  • 获取一个公司信息

Snipaste_2020-09-20_16-06-24

  • 获取集合资源(获取符合查询条件的公司资源)

Snipaste_2020-09-20_16-08-15

DELETE:删除一个公司信息

Snipaste_2020-09-20_16-09-31

PATCH:更新公司信息

Snipaste_2020-09-20_16-10-28

PUT:替换公司信息

Snipaste_2020-09-20_16-12-11

  • HEAD和GET几乎是一样的,只有一点不同:HEAD的API不应该返回相应的body,HEAD可以用来获取资源上的一些信息。
  • 比如在一个支持缓存的系统中,Head就可以返回某一个资源是否是有效的或者资源最近是否被更新了,也可以用来检查URI是否存在,即资源是否存在。
  • Head的代码基本上和Get是一致的,但它并不返回响应体

OPTIONS

  • 用来获取针对某个Api中的资源所支持的操作
  • 一般在响应消息头中添加Allow来表示所允许的Http方法

总结:

Snipaste_2020-09-20_16-13-24

Snipaste_2020-09-20_17-59-36

Http状态码

  • Http状态码主要是要来判断请求是否执行成功了,如果请求失败了,那失败的原因是什么,也就是谁应该为它负责。

  • 状态码可分为以下5类:

    1. 1xx:信息,服务器收到请求,需要请求方继续执行操作。
    2. 2xx:成功,服务器成功执行客户端所请求的操作。
    3. 3xx:重定向,需要进一步的操作以完成请求
    4. 4xx:客户端错误,请求包含语法错误或请求内容不正确。
    5. 5xx:服务端错误,服务器在处理请求的过程中发生了错误。
  • 以下是常见的状态码:

Snipaste_2020-09-20_16-34-15

Snipaste_2020-09-20_16-34-38

Snipaste_2020-09-20_16-34-59

Snipaste_2020-09-20_16-35-10

  • 还有一个422Unprocessable entity状态码,它通常是用来表示语义上有错误,即在服务器实体验证失败时可返回该状态码。

内容协商

  • 针对一个响应,当有多种表述格式可用时(json、xml等),如何选取一个最佳的表述,这就需要进行内容协商。
  • 当Http服务器对请求返回响应时,它不仅返回资源本身,也应在响应中指明资源的内容类型(Media Type),比如text/html,表示内容类型为text/html,前面text为主类型,html为子类型,当请求一个图片资源时,可以将它标记为image/jpg或image/gif

常见的媒体类型

Snipaste_2020-09-20_17-17-41

Accept:输出

  • 表示客户端可接受的响应内容类型
  • 如果请求中没有Accept的值,则服务器就会返回Api默认的媒体类型数据,当客户端就有可能无法解析服务器发送的数据,如果客户端添加了Accept Header,但服务器并不支持客户端请求的媒体类型,这时候,服务器就应该返回406Not Acceptable来告诉客户端不支持这个媒体类型的数据。

Content-Type:输入

  • 表示请求正文的Media Type(一般用于POST和PUT请求中)
  • 在Http Header中,Content-Type一般有三种:
    1. application/x-www-form-urlencoded:数据被编码为名称/值对。这是标准的编码格式。
    2. multipart/form-data: 数据被编码为一条消息,页上的每个控件对应消息中的一个部分。
    3. text/plain: 数据以纯文本形式(text/json/xml/html)进行编码,其中不含任何控件或格式字符。postman软件里标的是RAW。
  • 当action为get时候,浏览器用x-www-form-urlencoded的编码方式把form数据转换成一个字串(name1=value1&name2=value2…),然后把这个字串追加到url后面,用?分割,加载这个新的url。
  • 当action为post时候,浏览器把form数据封装到http body中,然后发送到server。 如果没有type=file的控件,用默认的application/x-www-form-urlencoded就可以了。 但是如果有type=file的话,就要用到multipart/form-data了。
  • 当action为post且Content-Type类型是multipart/form-data,浏览器会把整个表单以控件为单位分割,并为每个部分加上Content-Disposition(form-data或者file),Content-Type(默认为text/plain),name(控件name)等信息,并加上分割符(boundary)。

Http Header

  • Http Header分为请求头和响应头两部分
  • 常见的请求消息头

Snipaste_2020-09-20_17-35-56

Snipaste_2020-09-20_17-36-10

Snipaste_2020-09-20_17-36-36

  • 常见的响应消息头

Snipaste_2020-09-20_17-41-43

Snipaste_2020-09-20_17-42-09

Snipaste_2020-09-20_17-42-19

-------------本文结束感谢您的阅读-------------