• RESTful API编写指南
  • RESTful架构风格概述
  • REST架构风格

REST

1、什么是REST?

“REST不是一种协议,也不是一种文件格式,更不是一种开发框架。它是一系列设计约束的集合。” --是一组架构约束条件和原则。

REST描述的是在网络中client和server的一种交互形式;

REST本身不实用,实用的是如何设计 RESTful API(REST风格的网络接口)

REST(REpresentational State Transfer)–表现层状态转移–是一种软件架构风格。

Resource Representational State Transfer:资源在网络中以某种表现形式进行状态转移。

通过URL地址拼接上HTTP的动词(GET,POST,PUT,DELETE)来操作资源,进行增删改查。

URL定位资源,用HTTP动词(GET,POST,PUT,DELETE)描述操作。

2、REST用来干什么?

API(Application Programming Interface,应用程序编程接口),通俗点的解释就像一家公司,比如阿里、腾讯、百度等,它们可以提供一个API,然后码农可以编写软件与BAT等公司提供的API对接或交互。比如可以用手机的其他软件分享内容到微信/微信朋友圈或新浪微博等,这些软件就是与微信或微博API进行了交互。

REST就是一种建立API时需要遵守的一种规则/风格。-设计RESTful API
REST式的web服务是一种ROA(Resource-Oriented Architecture,面向资源的架构)。

Web 是分布式信息系统,为超文本文件和其它对象(资源)提供访问入口。

资源是Web架构的关键点,需要3个操作:识别 identify、表示 represent、 交互 interaction;通过这三个操作,又可以引出三个概念:统一资源标识符URI–识别资源、representation(html,xml,图片,视频等)–表示资源、通过协议(HTTP,FTP等)与资源进行交互。

REST选择通过HTTP协议和URI,利用client/server model对资源进行CRUD操作。

3、REST的基本概念:

五个关键词:

• 资源(Resource)• 资源的表述(Representation)• 状态转移(State Transfer)
• 统一接口(Uniform Interface)• 超媒体驱动(Hypermedia Driven)

  1. 服务器生成包含状态转移的表征数据,用来响应客户端对于一个资源的请求;
  2. 客户端借助这份表征数据,记录了当前的应用状态以及对应可转移状态的方式。

当然,为了要实现这一系列的功能,一个不可或缺的东西就是超文本(hypertext)或者说超媒体类型(hypermedia type)。这绝对不是一个简简单单的媒体类型(例如,JSON属性列表)可以做到的。

REST基础概念:

1)Resource资源 – 网络上所有事物都被抽象为资源;
2)Representation表现层 – 同一个资源具有多种表现形式(xml,json等);
3)每个资源都有一个唯一的资源标识符URI,对资源的各种操作不会改变资源标识符;
State Transfer 状态转化–客户端想要操作服务器,必须通过某种手段,让服务器发生表现层的状态转化。
4)使用统一的接口。处理资源使用POST,GET,PUT,DELETE操作类似创建,读取,更新和删除(CRUD)操作;
5)所有的操作都是无状态的(基于http协议)。每个请求是一个独立的请求。从客户端到服务器的每个请求都必须包含所有必要的信息,以便于理解。

REST本身不是架构,只是一种架构风格,理解它的时候要参考这个架构风格出现的环境所施加的约束条件。
REST的目的是“建立十年内不会过时的软件系统架构",所以它具备三个特点:1. 状态无关 —— 确保系统的横向拓展能力
2. 超文本驱动,Fielding的原话是”hypertext-driven" —— 确保系统的演化能力
3. 对 resource 相关的模型建立统一的原语,例如:uri、http的method定义等 —— 确保系统能够接纳多样而又标准的客户端从另外一个角度看,第一条保证服务端演化,第三条保证客户端演化,第二条保证应用本身的演化,这实在是一个极具抽象能力的方案。

4、REST操作

一般资源操作只有新增、删除、查询、更新,对应HTTP协议中四类请求:POST、DELETE、GET、PUT。
其中,DELETE、GET、PUT操作是幂等的。

【分布式系统中的幂等性】、【幂等性问题】【面试题:怎么实现接口的幂等性】

幂等性:

–使公式:f(x)=f(f(x)) 能够成立的数学性质

对同一个系统,使用同样的条件,一次请求和重复的多次请求对系统资源的影响是一致的。

举个最简单的例子,那就是支付,用户购买商品使用约支付,支付扣款成功,但是返回结果的时候网络异常,此时钱已经扣了,用户再次点击按钮,此时会进行第二次扣款,返回结果成功,用户查询余额返发现多扣钱了,流水记录也变成了两条...

5、什么是RESTful架构:

如果一个架构符合REST原则,就称它为RESTful架构。

(1)每一个URI代表一种资源;
(2)客户端和服务器之间,传递某资源的一个表现形式;
(3)客户端通过四个HTTP动词,对服务器端资源进行操作,实现"表现层状态转化"。

ps:

  • URI不应该包含动词,动词应该放在HTTP协议中;
    —如果某些动作使用HTTP动词表示不了,就应该把动作做成一种资源
  • URI中不应该加入版本号
    —不同的版本,可以理解成同一个资源的不同表现形式,应该采用同一个URI。
    —版本号可以在HTTP请求头信息的Accept字段中进行区分。

RESTful

看Url就知道要什么
看http method就知道干什么
看http status code就知道结果如何

1、为什么使用 RESTful 结构?/ RESTful结构的好处是什么?

1.JSP技术可以让我们在页面中嵌入Java代码,但是这样的技术实际上限制了我们的开发效率,因为需要我们Java工程师将html转换为jsp页面,并写一些脚本代码,或者前端代码。这样会严重限制我们的开发效率,也不能让我们的java工程师专注于业务功能的开发,所以目前越来越多的互联网公司开始实行前后端分离。

2.近年随着移动互联网的发展,各种类型的Client层出不穷,RESTful可以通过一套统一的接口为Web,iOS和Android提供服务。另外对于广大平台来说,比如微博开放平台,微信开放平台等,它们不需要有显式的前端,只需要一套提供服务的接口,RESTful无疑是最好的选择。

RESTful架构如下:

RESTful 结构的约束 描述 好处
1、客户端-服务器(Client-Server)分离 客户端和服务器是分离的 1、提高用户界面的便携性(操作简单)2、通过简化服务器提高可伸缩性(高性能,低成本)3、允许服务器和客户端分别进行改进和优化
2、无状态(Stateless) 从客户端的每个请求都要包含服务器所需要的所有信息 1、提高可见性(可以单独考虑每个请求)2、提高可靠性(更容易从局部故障中修复)3、提高可扩展性(降低了服务器资源使用)
3、缓存(Cachable) 服务器返回信息必须标记是否可以缓存:如果缓存,客户端可能会重用之前的信息发送请求 1、减少交互次数 2、减少交互的平均延迟
4、分层系统(Layered System) 系统组件不需要知道与之交流组件之外的事情。封装服务,引入中间层。 限制了系统的复杂性、提高可扩展性
5、统一接口(Uniform Interface) 提高交互的可见性、鼓励单独改善组件
6、支持按需代码(Code-On-Demand可选) 提高可扩展性

比较了三种架构风格之间的差别之后,从面向实用的角度来看,REST 架构风格可以为 Web 开发者带来三方面的利益:

  • 简单性
    采用 REST 架构风格,对于开发、测试、运维人员来说,都会更简单。可以充分利用大量 HTTP 服务器端和客户端开发库、Web 功能测试 / 性能测试工具、HTTP 缓存、HTTP 代理服务器、防火墙。这些开发库和基础设施早已成为了日常用品,不需要什么火箭科技(例如神奇昂贵的应用服务器、中间件)就能解决大多数可伸缩性方面的问题。

  • 可伸缩性
    充分利用好通信链各个位置的 HTTP 缓存组件,可以带来更好的可伸缩性。其实很多时候,在 Web 前端做性能优化,产生的效果不亚于仅仅在服务器端做性能优化,但是 HTTP 协议层面的缓存常常被一些资深的架构师完全忽略掉。

  • 松耦合
    统一接口 + 超文本驱动,带来了最大限度的松耦合。允许服务器端和客户端程序在很大范围内,相对独立地进化。对于设计面向企业内网的 API 来说,松耦合并不是一个很重要的设计关注点。但是对于设计面向互联网的 API 来说,松耦合变成了一个必选项,不仅在设计时应该关注,而且应该放在最优先位置。

一些对实时性要求很高的应用,REST 的表现不如 DO 和 RPC。所以需要针对具体的运行环境来具体问题具体分析。

2、之前及RESTful 用法对比:

之前的用法:

1)http://127.0.0.1/user/query/1 (GET请求方式,根据用户id查询用户数据);
2)http://127.0.0.1/user/save (POST请求方式,保存用户);
3)http://127.0.0.1/user/update (POST请求方式,修改用户信息);
4)http://127.0.0.1/user/delete/1 (GET/POST请求方式,根据用户id删除用户信息)

RESTful的用法:

1)http://127.0.0.1/user/1 (GET请求方式,根据用户id查询用户数据);
2)http://127.0.0.1/user (POST请求方式,保存用户);
3)http://127.0.0.1/user (PUT请求方式,修改用户信息);
4)http://127.0.0.1/user (DELETE请求方式,删除用户信息)

3、RESTful API 设计指南

0、some tricks:

  1. GET及HEAD必须是安全的。
  2. URL是区分大小写的;/Posts和/posts是不同的两个URL,可以指向不同的资源
  3. 建议URL以/作为结尾;/posts/和/posts也是两个不同的URL,可以对应不同的行为和资源
  4. 当URL中某一个片段(segment)由多个单词组成时,建议使用 - 来隔断单词,而不是使用 _

1、域名-URL root

应该尽量将API部署在专用域名之下

https://api.example.com

如果确定API很简单,不会有进一步扩展,可以考虑放在主域名下。

https://example.org/api/

2、版本号-API versioning

规范的API应该包含版本信息,在RESTful API中,最简单的包含版本的方法是将版本信息放到url中,如:

https://api.example.com/v1/

也可以使用HTTP header中的accept来传递版本信息,这也是GitHub API 采取的策略。

3、路径设计

在RESTful架构中,每个网址代表一种资源(resource),所以网址中不能有动词,只能有名词,而且所用的名词往往与数据库的表名对应,一般来说,数据库中的表都是同种记录的”集合”(collection),所以API中的名词也应该使用复数。

资源的URI格式:协议://域名/路径,它只是URL的子集,表征一个资源实体。比如,http://a.com/users/1。

举例来说,有一个API提供动物园(zoo)的信息,还包括各种动物和雇员的信息,则它的路径应该设计成下面这样。

https://api.example.com/v1/zoos
https://api.example.com/v1/animals
https://api.example.com/v1/employees

Server提供的RESTful API中,URL中只使用名词来指定资源,原则上不使用动词。“资源”是REST架构或者说整个网络处理的核心。比如:

http://api.qc.com/v1/newsfeed: 获取某人的新鲜; http://api.qc.com/v1/friends: 获取某人的好友列表;http://api.qc.com/v1/profile: 获取某人的详细信息;

4、HTTP动词

对于资源的具体操作类型,由HTTP动词表示。

常用的HTTP动词有下面五个(括号里是对应的SQL命令)。

用HTTP协议里的动词来实现资源的添加,修改,删除等操作。即通过HTTP动词来实现资源的状态转化

GET(SELECT):从服务器取出资源(一项或多项)。
POST(CREATE):在服务器新建一个资源。
PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)。
PATCH(UPDATE):在服务器更新资源(客户端提供改变的属性)。
DELETE(DELETE):从服务器删除资源。

下面是一些例子。

GET /zoos:列出所有动物园
POST /zoos:新建一个动物园
GET /zoos/ID:获取某个指定动物园的信息
PUT /zoos/ID:更新某个指定动物园的信息(提供该动物园的全部信息)
PATCH /zoos/ID:更新某个指定动物园的信息(提供该动物园的部分信息)
DELETE /zoos/ID:删除某个动物园
GET /zoos/ID/animals:列出某个指定动物园的所有动物
DELETE /zoos/ID/animals/ID:删除某个指定动物园的指定动物

又比如:

DELETE http://api.qc.com/v1/friends: 删除某人的好友 (在http parameter指定好友id)
POST http://api.qc.com/v1/friends: 添加好友
UPDATE http://api.qc.com/v1/profile: 更新个人资料

禁止使用: GET http://api.qc.com/v1/deleteFri

5、过滤信息(Filtering)

如果记录数量很多,服务器不可能都将它们返回给用户。API应该提供参数,过滤返回结果。

下面是一些常见的参数。


?limit=10:指定返回记录的数量
?offset=10:指定返回记录的开始位置。
?page=2&per_page=100:指定第几页,以及每页的记录数。
?sortby=name&order=asc:指定返回结果按照哪个属性排序,以及排序顺序。
?animal_type_id=1:指定筛选条件

参数的设计允许存在冗余,即允许API路径和URL参数偶尔有重复。比如,GET /zoo/ID/animals 与 GET /animals?zoo_id=ID 的含义是相同的。

6、状态码(Status Codes)

用 HTTP Status Code传递Server的状态信息。
服务器向用户返回的状态码和提示信息,常见的有以下一些(方括号中是该状态码对应的HTTP动词)。

200 OK - [GET]:服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)。
201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。
202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务)
204 NO CONTENT - [DELETE]:用户删除数据成功。
400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。
401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。
403 Forbidden - [*] 表示用户得到授权(与401错误相对),但是访问是被禁止的。
404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。
406 Not Acceptable - [GET]:用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。
410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。
422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。
500 INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。

状态码的完全列表参见这里。

7、错误处理(Error handling)

出错,需要返回错误原因.

如果状态码是4xx,就应该向用户返回出错信息。一般来说,返回的信息中将error作为键名,出错信息作为键值即可。

{error: “Invalid API key”}

8、接口即文档

Github的API就是这种设计,访问api.github.com会得到一个所有可用API的网址列表。这种设计被称为HATEOAS。


{current_user_url: "https://api.github.com/user",
current_user_authorizations_html_url: "https://github.com/settings/connections/applications{/client_id}",
authorizations_url: "https://api.github.com/authorizations",
code_search_url: "https://api.github.com/search/code?q={query}{&page,per_page,sort,order}",
emails_url: "https://api.github.com/user/emails",
emojis_url: "https://api.github.com/emojis",
events_url: "https://api.github.com/events",
feeds_url: "https://api.github.com/feeds",
followers_url: "https://api.github.com/user/followers",
following_url: "https://api.github.com/user/following{/target}",
gists_url: "https://api.github.com/gists{/gist_id}",
hub_url: "https://api.github.com/hub",
issue_search_url: "https://api.github.com/search/issues?q={query}{&page,per_page,sort,order}",
issues_url: "https://api.github.com/issues",
keys_url: "https://api.github.com/user/keys",
notifications_url: "https://api.github.com/notifications",
organization_repositories_url: "https://api.github.com/orgs/{org}/repos{?type,page,per_page,sort}",
organization_url: "https://api.github.com/orgs/{org}",
public_gists_url: "https://api.github.com/gists/public",
rate_limit_url: "https://api.github.com/rate_limit",
repository_url: "https://api.github.com/repos/{owner}/{repo}",
repository_search_url: "https://api.github.com/search/repositories?q={query}{&page,per_page,sort,order}",
current_user_repositories_url: "https://api.github.com/user/repos{?type,page,per_page,sort}",
starred_url: "https://api.github.com/user/starred{/owner}{/repo}",
starred_gists_url: "https://api.github.com/gists/starred",
team_url: "https://api.github.com/teams",
user_url: "https://api.github.com/users/{user}",
user_organizations_url: "https://api.github.com/user/orgs",
user_repositories_url: "https://api.github.com/users/{user}/repos{?type,page,per_page,sort}",
user_search_url: "https://api.github.com/search/users?q={query}{&page,per_page,sort,order}"
}

9、其他

(1)API的身份认证应该使用OAuth 2.0框架。
(2)服务器返回的数据格式,应该尽量使用JSON,避免使用XML。

由于RESTful风格的服务是无状态的,认证机制尤为重要。例如上文提到的员工工资,这应该是一个隐私资源,只有员工本人或其他少数有权限的人有资格看到,如果不通过权限认证机制对资源做一层限制,那么所有资源都以公开方式暴露出来,这是不合理的,也是很危险的。

认证机制解决的问题是,确定访问资源的用户是谁;权限机制解决的问题是,确定用户是否被许可使用、修改、删除或创建资源。权限机制通常与服务的业务逻辑绑定,因此权限机制需要在每个系统内部定制,而认证机制基本上是通用的,常用的认证机制包括 session auth(即通过用户名密码登录),basic auth,token auth和OAuth,服务开发中常用的认证机制为后三者。

From:知乎形象例子

单机软件的文件路径 = REST软件的Url
单机软件的打开操作 = REST软件HTTP的GET
单机软件的保存操作 = REST软件HTTP的POST

那么非REST架构软件(SOAP)和REST架构软件之间的的区别是啥呢?

其实区别就是在于对应的取资源的方式,SOAP用的是自己规定好的格式,而REST用的是大统一的Url格式。所以你想从SOAP软件中存取操作,必须事先知道它的读写格式;而REST,你只需要有一个浏览器就可以了。

RESTRESRful相关推荐

最新文章

  1. 全景图像拼接——基本流程
  2. 前端学习(2778):uni组件库的使用
  3. css3 背景等比例,纯 CSS,不用背景,实现图片等比例展示
  4. 百度相关搜索软件_不太热门的办公神器软件篇搜索相关
  5. 赢在微点答案专区英语_少儿英语课堂 语法教学游戏 全集
  6. Linux基础命令---tracepath
  7. php pathseparator,在PHP拥有与命名空间和通过set_include_path()的一个问题
  8. 利用SAP 0day,四分钟内黑掉华尔街
  9. node 加密解密模块_聊聊Node加密模块crypto加密原理的那些事
  10. 注意!最新.Net Framework与Exchange 的兼容性问题
  11. C语言中malloc,calloc,realloc,free的语法与作用
  12. 经典场景试题,测试用例编写
  13. 如何解决layui下select组件大数据卡顿问题
  14. 互联网热点自动获取工具的实现
  15. ES选举:Elasticsearch中Master选举完全解读
  16. Spring MVC参数化测试 - Junit Parameterized
  17. 【数据通信】具有路由 WSN 模拟器的随机方式移动(Matlab代码实现)
  18. 并购当当是海航自编自导的一场大戏
  19. 数字人民币将如何改变金融生态?
  20. 研究QQ、Fetion、Msn的socket连接

热门文章

  1. 前端web3入门脚本六:套利夹子机器人,羊毛党必备
  2. 内啡肽和多巴胺真的是对立关系吗?如何正确戒瘾?
  3. Spring Boot 完整讲解
  4. Python中类的基本用法
  5. k8s的自定义资源代码生成详解
  6. Coding4Fun.Controls的ToastPrompt小用
  7. 【第64篇】ConvNeXt V2论文翻译:ConvNeXt V2与MAE激情碰撞
  8. 软件项目管理与《拯救大兵瑞恩》
  9. 少样本苹果分类机器深度学习
  10. linux队列数据结构,网络设备发送队列相关数据结构及其创建函数 (linux网络子系统学习 第十节 )...