restful风格
- 概念:restful风格是一种软件架构风格,设计风格,而不是标准,只是提供了一种设计原则和和约束条件,它主要用于客户端和服务端用于交互类的软件。基于这个风格设计软件可以更简洁,更有层次,更易于实现缓存等机制。它本身没有什么使用性其核心价值在于设计出符合restful风格的网络接口。
- REST这个词,源于HTTP协议(1.0版和1.1版)的主要设计者表于2000年的博士论文《架构风格与基于网络的软件架构设计》REST它是 Representational State Transfer的缩写,表示表述性状态转移,这个说明比较晦涩抽象,难以理解。接下来拆开解释。首先这句话省略了主语“表述性”其实指的是“资源”的“表述性”;其次,要先理解一个重要的概念:资源的表述;最后再体会状态转移。
- 资源:REST是面向资源的,资源是网络上的一个实体,可以是一个文件、一张图像、一首歌曲、甚至是一种服务。资源可以设计得很抽象,但只要是具体信息,就可以是资源,因为资源的本质是一串二进制数据。并且每个资源必须有URL,通过URL来找到资源。
- 表述:资源在某个特定时刻的状态说明被称为表述(representation),表述由数据和描述数据的元数据(例如HTTP报文)组成。资源的表述有多种格式,这些格式也被称为MIME类型,例如文本的txt格式、图像的png格式、视频的mk格式等。一个资源可以有多种表述,例如服务器响应一个请求返回的资源可以是JSON格式的数据,也可以是XML格式的数据。
- 表述性状态转移:表述性状态转移的目的是操作资源,通过转移和控制资源的表述就能实现此目的。例如客户端可以向服务器发送GET请求,服务器将资源的表述转移到客户端;客户端也可以向服务器发送POST请求,传递表述改变服务器中的资源状态。
下面是对于restful风格的具体规范写法:
一.API的url
Url是用来定位资源的,要跟操作区分开,不能使用动词,要使用名词。
下面示例中的get,create,search等动词都不应该出现在resful风格的后端接口路径中。比如:
/api/getUser
/api/createUser
/api/serarchResult
/api/deleteUsers
当我们需要对单个用户进行操作时,根据操作的方式不同可能需要以下接口:
/api/getUser(用来获取某个用户的信息,,还需要以参数的方式传入用户id信息)
/api/updateUser(更新用户信息)
/api/deleteUser(删除用户信息)
/api/resetUser(重置用户信息)
可能在更新不同信息是使用不同的接口:
/api/updateUserName
/api/updateUserEamil
/api/updateUser
总结:以上三种情况的弊端在于,首先他们使用了动词,这样使的url更长了,其次对于一个资源实体进行不同操作就要使用不同的url,造成了url过多不好管理。
其实当你回头看url的术语时你就会更能理解这一点。Url的意思是统一资源定位符,这个术语已经很明确了,一个url应该用于定位资源,而不应该掺杂操作行为。
在resful架构url应该是这个样子的:
- url中不应该出现任何表示操作的动词,链接只能用于对应资源
- Url中应该单复数区分,推荐实践中永远用复数,比如get /api/users用于获取用户列表,如果需要获取单个用户,可以传入id.
- 按照资源逻辑层级,对url进行嵌套,比如一个成员属于团队,而这个团队又属于多个团队中的一个,那个获取某个成员的接口可能是这样:get /api/teams/123/members/234 表示获取123团队下的成员234的成员信息,按照类似的规则可以写出以下接口:
1./api/teams (获取团队列表)
2./api/teams/123 (获取名为123的团队)
3./api/teams/123/memers (获取名为123团队中的成员列表)
二.API,的请求方法
我们常用的请求方法就是GET,POST,PUT,DELETE,PATCH
接下来我们主要讲解一下 PUT , PATCH DELETE ,UPDATE(PUT,PATCH)
1.UPDATE(PUT,PATCH)
udpate用于资源的更新,用于更新的http方法有两个PUT 和 PATHCH,他们都应当被实现为幂等方法,及多次同样的更新请求应当对 服务器产生同样的副作用。
PUT 用于更新资源的全部信息,在请求的body中需要传入修改后的全部资源主体;
PATCH用于局部更新,在body中传入需要改动的资源字段
PATCH 的作用在于如果一个资源中有很多字段,在进行局部修改时,只需要传入需要修改的字段即可。否则在PUT状态下你不得不将整个资源全部发送给服务器,造成网络资源的极大浪费。
2.DELETE
资源的删除,相应的请求http方法就是DELETE。这个也应该被实现一个幂等的方法,如DELETE /api/users/123 用于删除服务器上id为123的资源,多次请求产生的副作用都是,服务器上id为123的资源不存在。
https://blog.csdn.net/qq_35075909/article/details/91522242
三:过滤
Rest风格的接口地址,表示的可能是单个资源,也可能是资源集合,当我们需要访问资源集合时,设计良好的接口应当接收参数允许只返回某些只满足特定条件的资源列表。
只提供关键词进行搜索,以及排序
Get api/users?Keywords=123&sort=createtime
支持根据字段进行过滤
Get api/users?Gender=1
当我们熟悉这且遵循这样的规范后,基本就可以看到一个rest风格的接口如何使用这个接口进行crud操作了。比如下面这个接口就表示搜索id为123的图书馆的书,并且书的信息里面包含关键词【game】,返回前十条满足条件的结果。
GET api/libararies/123/books?Keyword=game&sort=price&limit=10&offset=0
其他规范:
规则1:url结尾不应爱包含(/)
规则2:正斜杠分割符(/)必须用来指定层级关系
规则3:不得在url中使用下划线(_)
规则4:url路径中全部使用小写字母
规则5:使用_或-来让URI可读性更好 例如国内某知名开源中国社区,它上面的新闻地址就采用这种风格,http://www.oschina.net/news/38119/oschina-translate-reward-plan 。
规则6:使用?来过滤资源 很多人把?只当做参数传递,很容易造成url过于复杂,难以理解。可以把?用于对资源的过滤,例如/git/git/pulls用来表示git项目的所有推入请求,而/pulls?State=closed用来表示git项目中已经关闭的推入请求,这种url通常是对应一些特定条件的查询结果或算法运算结果。
四:使用http状态码处理错误
http状态码提供70个出错,我们只需要10左右:
200 -OK --一切正常,表示成功
201-OK--资源成功创建
202请求已被接收
204 操作已执行,但是没有返回数据
301资源被移除
303 重定向
304 资源没有被修改
400 参数错误(缺少,格式不匹配)
401 未授权
403 访问受限,访问过期
404 访问资源,服务器没找到
405 不允许的http方法
415 不支持的数据类型
429 请求过多被限制
500 系统内部错误
501 接口未实现
五:统一资源接口
Restful架构应该遵循统一接口原则,统一接口包含了一组受限的预定义的操作,无论什么样的资源,都是通过使用相同的接口进行资源访问,接口应该使用标准的http方法如:GET. POST PUT ,并遵循这些方法的语义。
如果按照HTTP方法的语义来暴露资源,那么接口将会拥有安全性和幂等性的特性,例如GET和HEAD请求都是安全的, 无论请求多少次,都不会改变服务器状态。而GET、HEAD、PUT和DELETE请求都是幂等的,无论对资源操作多少次, 结果总是一样的,后面的请求并不会产生比第一次更多的影响。
下面列出了GET,DELETE,PUT和POST的典型用法。
1.GET
- 安全且幂等
- 获取表示
- 变更时获取表示(缓存)
- 200(OK) - 表示已在响应中发出
- 204(无内容) - 资源有空表示
- 301(Moved Permanently) - 资源的URI已被更新
- 303(See Other) - 其他(如,负载均衡)
- 304(not modified)- 资源未更改(缓存)
- 400 (bad request)- 指代坏请求(如,参数错误)
- 404 (not found)- 资源不存在
- 406 (not acceptable)- 服务端不支持所需表示
- 500 (internal server error)- 通用错误响应
- 503 (Service Unavailable)- 服务端当前无法处理请求
2.POST
- 不安全且不幂等
- 使用服务端管理的(自动产生)的实例号创建资源
- 创建子资源
- 部分更新资源
- 如果没有被修改,则不过更新资源(乐观锁)
- 200(OK)- 如果现有资源已被更改
- 201(created)- 如果新资源被创建
- 202(accepted)- 已接受处理请求但尚未完成(异步处理)
- 301(Moved Permanently)- 资源的URI被更新
- 303(See Other)- 其他(如,负载均衡)
- 400(bad request)- 指代坏请求
- 404 (not found)- 资源不存在
- 406 (not acceptable)- 服务端不支持所需表示
- 409 (conflict)- 通用冲突
- 412 (Precondition Failed)- 前置条件失败(如执行条件更新时的冲突)
- 415 (unsupported media type)- 接受到的表示不受支持
- 500 (internal server error)- 通用错误响应
- 503 (Service Unavailable)- 服务当前无法处理请求
3.PUT
- 不安全但幂等
- 用客户端管理的实例号创建一个资源
- 通过替换的方式更新资源
- 如果未被修改,则更新资源(乐观锁)
- 200 (OK)- 如果已存在资源被更改
- 201 (created)- 如果新资源被创建
- 301(Moved Permanently)- 资源的URI已更改
- 303 (See Other)- 其他(如,负载均衡)
- 400 (bad request)- 指代坏请求
- 404 (not found)- 资源不存在
- 406 (not acceptable)- 服务端不支持所需表示
- 409 (conflict)- 通用冲突
- 412 (Precondition Failed)- 前置条件失败(如执行条件更新时的冲突)
- 415 (unsupported media type)- 接受到的表示不受支持
- 500 (internal server error)- 通用错误响应
- 503 (Service Unavailable)- 服务当前无法处理请求
4.DELETE
-
不安全但幂等
-
删除资源
-
200 (OK)- 资源已被删除
-
301 (Moved Permanently)- 资源的URI已更改
-
303 (See Other)- 其他,如负载均衡
-
400 (bad request)- 指代坏请求
-
404 (not found)- 资源不存在
-
409 (conflict)- 通用冲突
-
500 (internal server error)- 通用错误响应
-
503 (Service Unavailable)- 服务端当前无法处理请求
下面我们来看一些实践中常见的问题:
(1). POST和PUT用于创建资源时有什么区别?
POST和PUT在创建资源的区别在于,所创建的资源的名称(URI)是否由客户端决定。 例如为我的博文增加一个java的分类,生成的路径就是分类名/categories/java,那么就可以采用PUT方法。不过很多人直接把POST、GET、PUT、DELETE直接对应上CRUD,例如在一个典型的rails实现的RESTful应用中就是这么做的。
我认为,这是因为rails默认使用服务端生成的ID作为URI的缘故,而不少人就是通过rails实践REST的,所以很容易造成这种误解。
(2). 客户端不一定都支持这些HTTP方法吧?
的确有这种情况,特别是一些比较古老的基于浏览器的客户端,只能支持GET和POST两种方法。
在实践上,客户端和服务端都可能需要做一些妥协。例如rails框架就支持通过隐藏参数_method=DELETE来传递真实的请求方法, 而像Backbone这样的客户端MVC框架则允许传递_method传输和设置X-HTTP-Method-Override头来规避这个问题。
(3). 统一接口是否意味着不能扩展带特殊语义的方法?
统一接口并不阻止你扩展方法,只要方法对资源的操作有着具体的、可识别的语义即可,并能够保持整个接口的统一性。
像WebDAV就对HTTP方法进行了扩展,增加了LOCK、UPLOCK等方法。而github的API则支持使用PATCH方法来进行issue的更新,例如:
PATCH /repos/:owner/:repo/issues/:number
不过,需要注意的是,像PATCH这种不是HTTP标准方法的,服务端需要考虑客户端是否能够支持的问题。
统一资源接口对URI有什么指导意义?
统一资源接口要求使用标准的HTTP方法对资源进行操作,所以URI只应该来表示资源的名称,而不应该包括资源的操作。
通俗来说,URI不应该使用动作来描述。例如,下面是一些不符合统一接口要求的URI:- GET /getUser/1
- POST /createUser
- PUT /updateUser/1
- DELETE /deleteUser/1
(3).如果GET请求增加计数器,这是否违反安全性?
安全性不代表请求不产生副作用,例如像很多API开发平台,都对请求流量做限制。像github,就会限制没有认证的请求每小时只能请求60次。
但客户端不是为了追求副作用而发出这些GET或HEAD请求的,产生副作用是服务端"自作主张"的。
另外,服务端在设计时,也不应该让副作用太大,因为客户端认为这些请求是不会产生副作用的。参考地址:https://www.runoob.com/w3cnote/restful-architecture.html
推荐文章
《前端程序员面试笔试宝典》P162,https://book.douban.com/subject/30324146/
理解RESTful架构,http://www.ruanyifeng.com/blog/2011/09/restful.html
RESTful 架构风格概述,https://blog.igevin.info/posts/restful-architecture-in-general/
前后端分离与restful api介绍,https://zhuanlan.zhihu.com/p/32901317
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· DeepSeek在M芯片Mac上本地化部署