RESTful发展背景及简介网络应用程序，分为前端和后端两个部分。当前的发展趋势，就是前端设备层出不穷（手机、平板、桌面电脑、其他专用设备…）。因此，必须有一种统一的机制，方便不同的前端设备与后端进行通信。这导致API构架的流行，甚至出现"APIFirst"的设计思想。RESTful API是目前比较成熟的一套互联网应用程序的API设计理论。REST（Representational State Transfer）表述性状态转换，REST指的是一组架构约束条件和原则。 如果一个架构符合REST的约束条件和原则，我们就称它为RESTful架构。REST本身并没有创造新的技术、组件或服务，而隐藏在RESTful背后的理念就是使用Web的现有特征和能力， 更好地使用现有Web标准中的一些准则和约束。虽然REST本身受Web技术的影响很深， 但是理论上REST架构风格并不是绑定在HTTP上，只不过目前HTTP是唯一与REST相关的实例。RESTful 是一种网络应用程序的设计风格和开发方式，给出一种约定的标准，包含 api 接口规范、命名规则、URL、返回值、授权验证等，以下介绍几种主要的设计规范，我们在项目编写当中需要尽可能的去遵守。正确使用 HTTP 请求方法[scode type="share"]HTTP 请求有 5 种请求方法，对应 CRUD 操作，通常我们使用 GET 来做查询，POST 做提交。[/scode]GET：读取（Read）POST：新建（Create）PUT：更新（Update）PATCH：更新（Update），通常是部分更新DELETE：删除（DeleteURL[scode type="yellow"]URI规范[/scode]不用大写；用中杠-不用下杠_；参数列表要encode；URI中的名词表示资源集合，使用复数形式。[scode type="blue"]URI路径[/scode]既然上面 HTTP 请求方法已经为我们指定了请求的动作，那么请求的 url 路径只需要指定好需要请求的资源就可以了，它是名词，而非动词，或者动宾，比如 /articles 就是正确的，而下面的 URL 不是名词，所以是错误的：/getArticles/createNewCar/deleteAllRedCars[scode type="blue"]URL格式[/scode]URL 是不区分单数和复数的，通常的做法是当读取一个集合，比如 GET /articles，则表示读取所有文章，GET /articles/3 则表示读取某一篇文章。实际情况中我们应该避免 URL 嵌套过深常见的情况是，资源需要多级分类，因此很容易写出多级的 URL，比如获取某个作者的某一类文章。GET /authors/12/categories/2 这种 URL 不利于扩展，语义也不明确，往往要想一会，才能明白含义。更好的做法是，除了第一级，其他级别都用查询字符串表达。GET /authors/12?categories=2 下面是另一个例子，查询已发布的文章。我们可能会设计成下面的 URL。GET /articles/published 查询字符串的写法明显更好。GET /articles?published=true服务器响应接口的 API 返回的数据格式，不应该是纯文本，而应该是一个 JSON 对象，因为这样才能返回标准的结构化数据。所以，服务器回应的 HTTP 头的 Content-Type 属性要设为 application/json。 目前的前后端开发大部分数据的传输格式都是 JSON，因此定义一个统一规范的数据格式有利于前后端的交互与 UI 的展示。[collapse status="false" title="Request"]HTTP方法通过标准HTTP方法对资源CRUD：[scode type="blue"]安全性和幂等性[/scode]安全性：不会改变资源状态，可以理解为只读的；幂等性：执行1次和执行N次，对资源状态改变的效果是等价的。安全性/幂等性GET √ √POST × ×PUT × √DELETE × √[scode type="blue"]Format[/scode]只用以下常见的3种body format：1.Content-Type: application/jsonPOST /v1/animal HTTP/1.1 Host: api.example.org Accept: application/json Content-Type: application/json Content-Length: 24 { "name": "Gir", "animalType": "12" } 2.Content-Type: application/x-www-form-urlencoded (浏览器POST表单用的格式)POST /login HTTP/1.1 Host: example.com Content-Length: 31 Accept: text/html Content-Type: application/x-www-form-urlencoded username=root&password=Zion0101 3.Content-Type: multipart/form-data; boundary=—-RANDOM_jDMUxq4Ot5 (表单有文件上传时的格式)[scode type="blue"]Content Negotiation[/scode]资源可以有多种表示方式，如json、xml、pdf、excel等等，客户端可以指定自己期望的格式，通常有两种方式：1.http header Accept：（q为各项格式的偏好程度）Accept:application/xml;q=0.6,application/atom+xml;q=1.0 2.url中加文件后缀：/zoo/1.json[/collapse][collapse status="false" title="Response"]response 的 body 直接就是数据，不要做多余的包装[scode type="blue"]错误处理[/scode]不要发生了错误但给2xx响应，客户端可能会缓存成功的http请求；正确设置http状态码，不要自定义；Response body 提供 1) 错误的代码（日志/问题追查）；2) 错误的描述文本（展示给用户）。对第三点的实现稍微多说一点：Java 服务器端一般用异常表示 RESTful API 的错误。API 可能抛出两类异常：业务异常和非业务异常。业务异常由自己的业务代码抛出，表示一个用例的前置条件不满足、业务规则冲突等，比如参数校验不通过、权限校验失败。非业务类异常表示不在预期内的问题，通常由类库、框架抛出，或由于自己的代码逻辑错误导致，比如数据库连接失败、空指针异常、除0错误等等。业务类异常必须提供2种信息：如果抛出该类异常，HTTP 响应状态码应该设成什么；异常的文本描述；在Controller层使用统一的异常拦截器：设置 HTTP 响应状态码：对业务类异常，用它指定的 HTTP code；对非业务类异常，统一500；Response Body 的错误码：异常类名Response Body的错误描述：对业务类异常，用它指定的错误文本；对非业务类异常，线上可以统一文案如“服务器端错误，请稍后再试”，开发或测试环境中用异常的stacktrace，服务器端提供该行为的开关。[scode type="blue"]常用的http状态码及使用场景[/scode]状态码 / 使用场景400 bad request 常用在参数校验401 unauthorized 未经验证的用户，常见于未登录。如果经过验证后依然没权限，应该 403（即 authentication 和 authorization 的区别）。403 forbidden 无权限404 not found 资源不存在500 internal server error 非业务类异常503 service unavaliable 由容器抛出，自己的代码不要抛这个异常[/collapse]