REST以及RESTful

  java作为一门后端语言,其厉害之处在于web,大家比较熟知的各种网络应用,java都能做,那么在这个移动优先的时代,如何继续发挥java的强大呢。通常是让java作为一个app的服务端,为app客户端提供数据,做业务逻辑,所以我们用java来写接口,app客户端访问接口返回json文件进行解析,最后实现业务逻辑。这种方式就是我们通常所说的restful架构风格的api。

  restful是一种架构思想,最初由Roy T. Fielding(HTTP/1.1协议专家组负责人)在其2000年的博士学位论文中提出。HTTP就是该架构风格的一个典型应用,其核心思想就是前后端分离,前端通过http请求,如www.xxxx.com/demo/username/password  来访问后端的接口,然后后端将处理好的数据封装为json返回,这样,后端只需关注具体逻辑 提供接口,而前端只关心界面,提高了程序解耦性。 

  在移动优先的时代,restful极为重要。通常一套后台可以让多种终端访问,包括移动端,pc端。

  在java中比较容易实现restful的是SpringMVC框架,他提供了一套处理json的注解。通过@ResponseBody返回json数据,通过@ResquestBody解析json。

  

 

REST(Representational State Transfer)表象化状态转变(表述性状态转变),在2000年被提出,基于HTTP、URI、XML、JSON等标准和协议,支持轻量级、跨平台、跨语言的架构设计。是Web服务的一种新的架构风格(一种思想)

什么是轻量级:

代码不被侵入(正例:SpringMVC中不用接口和继承,仅用注解完成。反例:Struts中每一个Action都要继承核心控制器),轻量级跟包大小无关。耦合性越低,越轻量。

REST架构的主要原则

  • 网络上每一个资源都有一个资源标志符,可以用来唯一地标识该资源

  • 对资源的操作不会改变标识符。

  • 同一资源有多种表现形式(xml、json)

  • 所有操作都是无状态的(Stateless)

符合上述REST原则的架构方式称为 RESTful

RESTful资源操作

http方法 资源操作 幂等 安全
GET SELECT 
POST  INSERT 
PUT  UPDATE 
DELETE  DELETE 

幂等性:对同一REST接口的多次访问,得到的资源状态是相同的。

安全性:对该REST接口访问,不会使服务器端资源的状态发生改变。

注意,默认情况下,PUT请求是无法提交表单数据的,在Spring MVC项目中需要在web.xml中添加过滤器解决:

<!-- 解决PUT请求无法提交表单数据的问题 --> 
<filter> 
<filter-name>HttpMethodFilter</filter-name> 
<filter-class>org.springframework.web.filter.HttpPutFormContentFilter</filter-class> 
</filter> 
<filter-mapping> 
<filter-name>HttpMethodFilter</filter-name> 
<url-pattern>/*</url-pattern> 
</filter-mapping> 

URL设计

  • 动词的覆盖

有些客户端只能使用GETPOST两种方法。服务器必须接受POST模拟其他三个方法(PUTPATCHDELETE)。这时,客户端发出的 HTTP 请求,要加上X-HTTP-Method-Override属性,告诉服务器应使用哪一个动词,覆盖POST方法。

POST /api/Person/4 HTTP/1.1  
X-HTTP-Method-Override: PUT
//上面代码中,X-HTTP-Method-Override指定本次请求的方法是PUT,而不是POST。
  • 宾语必须是名词

宾语就是 API 的 URL,是 HTTP 动词作用的对象。它应该是名词,不能是动词。比如,/articles这个 URL 就是正确的,而下面的 URL 不是名词,所以都是错误的。

/getAllCars
/createNewCar
/deleteAllRedCars
  • 复数 URL

既然 URL 是名词,那么应该使用复数,还是单数,没有统一的规定,但是常见的操作是读取一个集合,比如GET /articles(读取所有文章),这里明显应该是复数。

为了统一起见,建议都使用复数 URL,比如GET /articles/2要好于GET /article/2

  • 避免多级 URL

常见的情况是,资源需要多级分类,因此很容易写出多级的 URL

//比如获取某个作者的某一类文章。这种 URL 不利于扩展,语义也不明确,往往要想一会,才能明白含义。
GET /authors/12/categories/
//更好的做法是,除了第一级,其他级别都用查询字符串表达。
GET /authors/12?categories=2

//下面是另一个例子,查询已发布的文章。你可能会设计成下面的 URL。
GET /articles/published
//查询字符串的写法明显更好。
GET /articles?published=true

接口示例

//传统URL请求格式:
http://127.0.0.1/user/query/1 GET 根据用户id查询用户数据
http://127.0.0.1/user/save POST 新增用户
http://127.0.0.1/user/update POST 修改用户信息
http://127.0.0.1/user/delete GET/POST 删除用户信息

//RESTful请求格式:
http://127.0.0.1/user/1 GET 根据用户id查询用户数据
http://127.0.0.1/user POST 新增用户
http://127.0.0.1/user PUT 修改用户信息
http://127.0.0.1/user DELETE 删除用户信息

服务器回应

  • 不要返回纯本文

API 返回的数据格式,不应该是纯文本,应该是一个 JSON 对象,这样才能返回标准的结构化数据。所以,服务器回应的 HTTP 头的Content-Type属性要设为application/json

客户端请求时,也要明确告诉服务器,可以接受 JSON 格式,即请求的 HTTP 头的ACCEPT属性也要设成application/json。如:

GET /orders/2 HTTP/1.1 
Accept: application/json
  • 发生错误时,不要返回 200 状态码
//有一种不恰当的做法是,即使发生错误,也返回200状态码,把错误信息放在数据体里面,就像下面这样,解析数据体以后,才能得知操作失败。这张做法实际上取消了状态码,这是完全不可取的。
HTTP/1.1 200 OK
Content-Type: application/json

{
  "status": "failure",
  "data": {
    "error": "Expected at least two items in list."
  }
}

//正确的做法是,状态码反映发生的错误,具体的错误信息放在数据体里面返回。
HTTP/1.1 400 Bad Request
Content-Type: application/json

{
  "error": "Invalid payoad.",
  "detail": {
     "surname": "This field is required."
  }
}
  • 提供链接

API 的使用者未必知道,URL 是怎么设计的。一个解决方法是,在回应中,给出相关链接,便于下一步操作。这样的话,用户只要记住一个 URL,就可以发现其他的 URL,这种方法叫做 HATEOAS。

//举例来说,GitHub 的 API 都在 api.github.com 这个域名。访问它,就可以得到其他 URL。
{
  ...
  "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",
  ...
}
//上面的回应中,挑一个 URL 访问,又可以得到别的 URL。对于用户来说,不需要记住 URL 设计,只要从 api.github.com 一步步查找就可以了。 //HATEOAS 的格式没有统一规定,上面例子中,GitHub 将它们与其他属性放在一起。更好的做法应该是,将相关链接与其他属性分开。 HTTP/1.1 200 OK Content-Type: application/json { "status": "In progress", "links": {[ { "rel":"cancel", "method": "delete", "href":"/api/status/12345" } , { "rel":"edit", "method": "put", "href":"/api/status/12345" } ]} }

 

posted @ 2019-04-04 18:27  WhatAreWords  阅读(190)  评论(0编辑  收藏  举报