RESTful6大原则及实践

六大原则

1. C-S架构

数据的存储在Server端,Client端只需使用就行。两端彻底分离的好处使client端代码的可移植性变强,Server端的拓展性变强。两端单独开发,互不干扰。

2. 无状态

http请求本身就是无状态的,基于C-S架构,客户端的每一次请求带有充分的信息能够让服务端识别。请求所需的一些信息都包含在URL的查询参数、header、body,服务端能够根据请求的各种参数,无需保存客户端的状态,将响应正确返回给客户端。无状态的特征大大提高的服务端的健壮性和可拓展性。

当然这总无状态性的约束也是有缺点的,客户端的每一次请求都必须带上相同重复的信息确定自己的身份和状态(这也是必须的),造成传输数据的冗余性,但这种确定对于性能和使用来说,几乎是忽略不计的。

3.统一的接口

这个才是REST架构的核心,统一的接口对于RESTful服务非常重要。客户端只需要关注实现接口就可以,接口的可读性加强,使用人员方便调用。

4.一致的数据格式

服务端返回的数据格式要么是XML,要么是Json(获取数据),或者直接返回状态码,有兴趣的可以看看博客园的开放平台的操作数据的api,post、put、patch都是返回的一个状态码 。

自我描述的信息,每项数据应该是可以自我描述的,方便代码去处理和解析其中的内容。比如通过HTTP返回的数据里面有 [MIME type ]信息,我们从MIME type里面可以知道数据的具体格式,是图片,视频还是JSON,客户端通过body内容、查询串参数、请求头和URI(资源名称)来传送状态。服务端通过body内容,响应码和响应头传送状态给客户端。这项技术被称为超媒体(或超文本链接)。

除了上述内容外,HATEOS也意味着,必要的时候链接也可被包含在返回的body(或头部)中,以提供URI来检索对象本身或关联对象。下文将对此进行更详细的阐述。

如请求一条微博信息,服务端响应信息应该包含这条微博相关的其他URL,客户端可以进一步利用这些URL发起请求获取感兴趣的信息,再如分页可以从第一页的返回数据中获取下一页的URT也是基于这个原理。

4.系统分层

客户端通常无法表明自己是直接还是间接与端服务器进行连接,分层时同样要考虑安全策略。

5.可缓存

在万维网上,客户端可以缓存页面的响应内容。因此响应都应隐式或显式的定义为可缓存的,若不可缓存则要避免客户端在多次请求后用旧数据或脏数据来响应。管理得当的缓存会部分地或完全地除去客户端和服务端之间的交互,进一步改善性能和延展性。

6.按需编码、可定制代码(可选)

服务端可选择临时给客户端下发一些功能代码让客户端来执行,从而定制和扩展客户端的某些功能。比如服务端可以返回一些 Javascript 代码让客户端执行,去实现某些特定的功能。提示:REST架构中的设计准则中,只有按需编码为可选项。如果某个服务违反了其他任意一项准则,严格意思上不能称之为RESTful风格。

实践

1. 版本

如github开放平台 https://developer.github.com/v3/
就是将版本放在url,简洁明了,这个只有用了才知道,一般的项目加版本v1,v2,v3?好吧,这个加版本估计只有大公司大项目才会去使用,说出来不怕尴尬,我真没用过。有的会将版本号放在header里面,但是不如url直接了当。

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

2.参数命名规范

query parameter可以采用驼峰命名法,也可以采用下划线命名的方式,推荐采用下划线命名的方式,据说后者比前者的识别度要高,可能是用的人多了吧,因人而异,因团队规范而异吧

https://example.com/api/users/today_login 获取今天登陆的用户
https://example.com/api/users/today_login&sort=login_desc 获取今天登陆的用户、登陆时间降序排列

3.url命名规范

API 命名应该采用约定俗成的方式,保持简洁明了。在RESTful架构中,每个url代表一种资源所以url中不能有动词,只能有名词,并且名词中也应该使用复数。实现者应使用相应的Http动词GET、POST、PUT、PATCH、DELETE、HEAD来操作这些资源即可

不规范的的url,冗余没有意义,形式不固定,不同的开发者还需要了解文档才能调用。

https://example.com/api/getallUsers GET 获取所有用户
https://example.com/api/getuser/1 GET 获取标识为1用户信息
https://example.com/api/user/delete/1 GET/POST 删除标识为1用户信息
https://example.com/api/updateUser/1 POST 更新标识为1用户信息
https://example.com/api/User/add POST 添加新的用户

规范后的RESTful风格的url,形式固定,可读性强,根据users名词和http动词就可以操作这些资源

https://example.com/api/users GET 获取所有用户信息
https://example.com/api/users/1 GET 获取标识为1用户信息
https://example.com/api/users/1 DELETE 删除标识为1用户信息
https://example.com/api/users/1 Patch 更新标识为1用户部分信息,包含在body中
https://example.com/api/users POST 添加新的用户

4. 统一返回数据格式

对于合法的请求应该统一返回数据格式,这里演示的是json

  • code——包含一个整数类型的HTTP响应状态码。

  • status——包含文本:”success”,”fail”或”error”。HTTP状态响应码在500-599之间为”fail”,在400-499之间为”error”,其它均为”success”(例如:响应状态码为1XX、2XX和3XX)。这个根据实际情况其实是可要可不要的。

  • message——当状态值为”fail”和”error”时有效,用于显示错误信息。参照国际化(il8n)标准,它可以包含信息号或者编码,可以只包含其中一个,或者同时包含并用分隔符隔开。

  • data——包含响应的body。当状态值为”fail”或”error”时,data仅包含错误原因或异常名称、或者null也是可以的

返回成功的响应json格式

{
  "code": 200,
  "message": "success",
  "data": {
    "userName": "123456",
    "age": 16,
    "address": "beijing"
  }
}

返回失败的响应json格式

{
  "code": 401,
  "message": "error  message",
  "data": null
}

下面这个ApiResult的泛型类是在项目中用到的,拓展性强,使用方便。返回值使用统一的 ApiResult 或 ApiResult 错误返回 使用 ApiResult.Error 进行返回;成功返回,要求使用 ApiResult.Ok 进行返回

public class ApiResult: ApiResult
    {
        public new static ApiResult<T> Error(string message)
        {
            return new ApiResult<T>
            {
                Code = 1,
                Message = message,
            };
        }
        [JsonProperty("data")]
        public T Data { get; set; }
    }
    public class ApiResult
    {
        public static ApiResult Error(string message)
        {
            return new ApiResult
            {
                Code = 1,
                Message = message,
            };
        }

        public static ApiResult<T> Ok<T>(T data)
        {
            return new ApiResult<T>()
            {
                Code = 0,
                Message = "",
                Data = data
            };
        }
        /// <summary>
        /// 0 是 正常 1 是有错误
        /// </summary>
        [JsonProperty("code")]
        public int Code { get; set; }
        [JsonProperty("msg")]
        public string Message { get; set; }

        [JsonIgnore]
        public bool IsSuccess => Code == 0;
    }

5. http状态码

在之前开发的xamarin android博客园客户端的时候,patch、delete、post操作时body响应里面没有任何信息,仅仅只有http status code。HTTP状态码本身就有足够的含义,根据http status code就可以知道删除、添加、修改等是否成功。(ps:有点linux设计的味道哦,没有返回消息就是最好的消息,表示已经成功了)服务段向用户返回这些状态码并不是一个强制性的约束。简单点说你可以指定这些状态,但是不是强制的。常用HTTP状态码对照表 HTTP状态码也是有规律的

  • 1**请求未成功

  • 2**请求成功、表示成功处理了请求的状态代码。

  • 3**请求被重定向、表示要完成请求,需要进一步操作。通常,这些状态代码用来重定向。

  • 4** 请求错误这些状态代码表示请求可能出错,妨碍了服务器的处理。

  • 5**(服务器错误)这些状态代码表示服务器在尝试处理请求时发生内部错误。这些错误可能是服务器本身的错误,而不是请求出错。

6. 合理使用query parameter

在请求数据时,客户端经常会对数据进行过滤和分页等要求,而这些参数推荐采用HTTP Query Parameter的方式实现

比如设计一个最近登陆的所有用户
https://example.com/api/users?recently_login_day=3
搜索用户,并按照注册时间降序
https://example.com/api/users?recently_login_day=3
搜索用户,并按照注册时间升序、活跃度降序
https://example.com/api/users?q=key&sort=create_title_asc,liveness_desc
关于分页,看看博客园开放平台分页获取精华区博文列表
https://api.cnblogs.com/api/blogposts/@picked?pageIndex={pageIndex}&pageSize={pageSize}
返回示例:
[ 
{
“Id”: 1,
“Title”: “sample string 2”,
“Url”: “sample string 3”,
“Description”: “sample string 4”,
“Author”: “sample string 5”,
“BlogApp”: “sample string 6”,
“Avatar”: “sample string 7”,
“PostDate”: “2017-06-25T20:13:38.892135+08:00”,
“ViewCount”: 9,
“CommentCount”: 10,
“DiggCount”: 11
},
{
“Id”: 1,
“Title”: “sample string 2”,
“Url”: “sample string 3”,
“Description”: “sample string 4”,
“Author”: “sample string 5”,
“BlogApp”: “sample string 6”,
“Avatar”: “sample string 7”,
“PostDate”: “2017-06-25T20:13:38.892135+08:00”,
“ViewCount”: 9,
“CommentCount”: 10,
“DiggCount”: 11
}
]

7. 多表、多参数连接查询如何设计URL

这是一个比较头痛的问题,在做单个实体的查询比较容易和规范操作,但是在实际的API并不是这么简单而已,这其中常常会设计到多表连接、多条件筛选、排序等。比如我想查询一个获取在6月份的订单中大于500元的且用户地址是北京,用户年龄在22岁到40岁、购买金额降序排列的订单列表

https://example.com/api/orders?order_month=6&order_amount_greater=500&address_city=北京&sort=order_amount_desc&age_min=22&age_max=40

从这个URL上看,参数众多、调用起来还得一个一个仔细对着,而且API本身非常不容易维护,命名看起来不是很容易,不能太长,也不能太随意。

在.net WebAPI总我们可以使用属性路由,属性路由就是讲路由附加到特定的控制器或操作方法上装饰Controll及其使用[Route]属性定义路由的方法称为属性路由。

这种好处就是可以精准地控制URL,而不是基于约定的路由,简直就是为这种多表查询量身定制似的的。从webapi 2开发,现在是RESTful API开发中最推荐的路由类型。我们可以在Controll中标记Route

[Route(“api/orders/{address}/{month}”)]

Action中的查询参数就只有金额、排序、年龄。减少了查询参数、API的可读性和可维护行增强了。

https://example.com/api/orders/beijing/6?order_amount_greater=500&sort=order_amount_desc&age_min=22&age_max=40

这种属性路由比如在博客园开放的API也有这方面的应用,如获取个人博客随笔列表

请求方式:GET
请求地址:https://api.cnblogs.com/api/blogs/{blogApp}/posts?pageIndex={pageIndex}
(ps:blogApp:博客名)
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1. 什么是 RESTful 架构风格?它有哪些特点? 回答:RESTful 是一种设计风格或架构模式,用于构建基于网络的应用程序和服务。它基于 HTTP 协议,通过提供统一的接口和标准的方式来处理资源和操作,实现了分布式系统中的数据交互和通信。RESTful 架构风格强调资源的概念,每个资源都有一个唯一的标识符(URI)和一组操作(HTTP 方法)来处理它们。常见的 HTTP 方法包括 GET、POST、PUT 和 DELETE。RESTful 架构风格被广泛应用于 Web 应用程序、移动应用程序和云服务等领域。 2. 谈谈你对 HTTP 方法的理解,以及它们在 RESTful 架构中的作用? 回答:HTTP 方法是用于表示客户端对服务器资源的操作类型的一种机制。常见的 HTTP 方法包括 GET、POST、PUT 和 DELETE 等。在 RESTful 架构中,HTTP 方法用于表示对资源的不同操作类型,例如 GET 用于获取资源,POST 用于新增资源,PUT 用于更新资源,DELETE 用于删除资源等。 3. RESTful 架构中的资源是什么?它们如何被标识和访问? 回答:RESTful 架构中的资源是指应用程序中的一些实体或对象,例如用户、订单、商品等。每个资源都有一个唯一的标识符(URI),用于标识和访问该资源。URI 应该是有意义的和易于理解的,例如 /users,/users/1 等。 4. 什么是 URI?在 RESTful 架构中有什么作用? 回答:URI(Uniform Resource Identifier)是用于标识和访问 Web 上的资源的一种标识符。在 RESTful 架构中,URI 是用于标识和访问资源的唯一标识符,每个资源都有一个对应的 URI。URI 应该是有意义的和易于理解的,例如 /users,/users/1 等。 5. RESTful 架构中的状态转移是什么?有哪些状态转移? 回答:RESTful 架构中,状态转移是指客户端通过 HTTP 方法对资源进行操作的过程。常见的状态转移包括: - GET:用于获取资源的信息,不会对资源进行修改。 - POST:用于新增资源或提交数据,对资源进行修改。 - PUT:用于更新资源,通常需要提供完整的资源信息。 - DELETE:用于删除资源。 6. RESTful 架构中的资源表示是什么?它有哪些常见的格式? 回答:RESTful 架构中的资源表示是指客户端和服务器之间传输的资源表现形式。常见的资源表示格式包括: - JSON:一种轻量级的数据交换格式。 - XML:一种标记语言,用于描述数据结构。 - HTML:一种用于 Web 页面的标记语言。 - 文本:一种纯文本格式。 7. 什么是 HATEOAS?在 RESTful 架构中有什么作用? 回答:HATEOAS(Hypermedia As The Engine Of Application State)是一种 RESTful 架构中的概念,强调资源之间的关系和状态转移的动态性。HATEOAS 要求每个资源都包含有关其自身的信息以及如何与其他资源进行交互的信息。通过 HATEOAS,客户端可以在访问资源时自动获取其相关资源的 URI,从而实现资源之间的自动导航和状态转移。 8. RESTful 架构相对于传统的 RPC 和 SOAP 有哪些优势? 回答:相对于传统的 RPC 和 SOAP,RESTful 架构具有以下优势: - 可伸缩性:RESTful 架构基于 HTTP 协议,可以使用现有的 Web 技术和基础设施,具有更好的可伸缩性。 - 简单性:RESTful 架构采用统一的接口和标准的方式来处理资源和操作,具有更好的可读性和易用性。 - 松耦合性:RESTful 架构强调资源的概念,客户端和服务器之间不需要共享任何状态信息,具有更好的松耦合性。 - 可见性:RESTful 架构中的资源和操作都是可见的,客户端可以很容易地了解应用程序的结构和功能。 - 缓存性:RESTful 架构中的资源可以使用 HTTP 协议的缓存机制,可以提高性能和可用性。 9. RESTful 架构中如何处理错误和异常? 回答:在 RESTful 架构中,错误和异常应该以标准的 HTTP 状态码来表示。常见的 HTTP 状态码包括: - 200 OK:表示请求成功。 - 201 Created:表示资源创建成功。 - 204 No Content:表示请求成功,但响应中没有返回任何内容。 - 400 Bad Request:表示客户端请求有误。 - 401 Unauthorized:表示客户端未经授权。 - 404 Not Found:表示请求的资源不存在。 - 500 Internal Server Error:表示服务器内部错误。 10. 谈谈你对 RESTful API 设计的经验和实践。你最近设计的一个 RESTful API 是什么?它的设计有哪些值得称道的特点? 回答:这个问题需要回答者根据自己的实际经验和设计情况来回答。一般来说,一个好的 RESTful API 应该具有以下特点: - 符合 RESTful 架构风格的设计原则。 - 使用清晰、简洁、易于理解的 URI 来标识和访问资源。 - 使用恰当的 HTTP 方法来表示不同的状态转移。 - 使用恰当的 HTTP 状态码来表示错误和异常。 - 使用恰当的资源表示格式和内容协商机制。 - 提供良好的文档和测试工具。 - 提供安全和身份认证机制。 - 具有良好的性能和可伸缩性。 例如,一个简单的 RESTful API 可以是一个用户管理系统,包括获取用户列表、获取单个用户、新增用户、更新用户和删除用户等操作。其 URI 可以如下所示: - GET /users:获取用户列表。 - GET /users/{id}:获取单个用户。 - POST /users:新增用户。 - PUT /users/{id}:更新用户。 - DELETE /users/{id}:删除用户。 该 API 的设计遵循 RESTful 架构风格的设计原则,使用清晰、简洁、易于理解的 URI 来标识和访问资源,使用恰当的 HTTP 方法来表示不同的状态转移,并提供了良好的文档和测试工具。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值