随着前后端分离越来越普遍,后端接口规范也就越来越重要了。一套良好的接口规范可以提升工作效率,减少沟通障碍。通常我们都会采用RestfulApi方式来提供接口,使用JSON来传输数据。
Restful是一种软件架构风格,不是标准。既然不是标准,可以遵守,也可以不遵守!!!
在实际开发中,本着提高工作效率、降低沟通障碍
的初衷,使用Restful规范去开发接口时,对于6要素有着以下的要求:
资源:所有在服务器(电脑)保存的数据(如:音乐/视频/文章/个人信息…)都是服务器端资源.(项目中资源通常都是指的数据表的一条数据)
URI(Uniform Resource Identifier):统一资源标志符,包含URL和URN。
URL(Uniform Resource Locator):统一资源定位符
URN(Uniform Resource Name):统一资源名
接口通信协议
接口域名
端口号
接口版本
请求路径
对于资源,一般有4个操作:CURD(增/删/改/查)
以新闻资源为例:URI及HTTP动词设计如下 (资源名称推荐写复数形式)
HTTP动词 | URI路径 | 说明 |
---|---|---|
GET | http://域名/news | 获取列表数据 |
GET | http://域名/news/:id | 根据id获取一条数据 |
POST | http://域名/news | 添加一条数据 |
PUT | http://域名/news/:id | 根据id修改一条数据 |
DELETE | http://域名/news/:id | 根据id“删除“一条数据 |
上述形式的URI路径(路由)称之为资源路由
。
通常也叫做请求参数或查询字符串(“?id=1&age=213
”)。
成功发送的请求必有响应(响应可能没有响应体,但是状态码肯定有),每个响应都会有一个状态码。在Restful风格编写接口时常见的HTTP请求状态码有:
状态码 | 含义 | 说明 |
---|---|---|
200 | OK | 操作成功, 并返回数据 |
400 | Bad Request | 请求语法错误 |
403 | Forbidden | 请求没有权限的资源 |
404 | Not Found | 没有找到请求的资源 |
405 | Method Not Allowed | 请求动词使用错误 |
500 | Internal Server Error | 服务器(配置)内部错误 |
更为详尽的状态码参考:
**GET **
200(OK) - 表示已在响应中发出
204(No Content) - 资源有空表示
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)- 服务端当前无法处理请求
**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)- 服务当前无法处理请求
**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)- 服务当前无法处理请求
**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)- 服务端当前无法处理请求
如果状态码是4xx
或者5xx
, 需要告诉客户端对应的错误信息。通常以Json格式返回,形式如下:
{
'error': '错误信息',
'code': '错误编号',
'msg': '资源没找到',
'message': 'xxxx',
'text': 'xxxx',
'reason': 'xxxxxx'
}
针对不同的操作,服务需要返回的结果应该符合这样的规范:
GET /collections – 返回资源列表(数组对应的json格式)
GET /collections/:id – 返回单个资源 eg. /collections/1
POST /collections – 返回新生成的资源
PUT /collections/:id – 返回资源的完整属性
DELETE /collections/:id – 返回204状态码+空文档
实际开发中,通常会将状态码、错误信息、返回数据,都放到返回结果中(一般以json格式返回)。例如:
{
"code":200,
"msg":"success",
"goods":{
"id":1,
"goods_name":"华为P100 pro plus",
"goods_price": 9999.99,
"currency": "CNY",
"stock": 1288,
.......
}
}
返回的数据中,节点的
key
名字要遵循见名知义
前后端分离式开发需要进行数据交互,传输的数据被偷窥、被抓包、被伪造时有发生,那么如何设计一套比较安全的API接口方案呢?
并不是所有的接口都需要考虑安全的,有些接口是公开的,任何人只要知道地址都可以调用,对于一些项目中需要用户登录才能访问的接口才需要考虑安全问题。
一般解决的方案有以下几类:
关于
JWT
:
Json web token(JWT),是基于token的鉴权机制,类似于http协议也是无状态的,它不需要在服务端去保留用户的认证信息或者会话信息,为应用的扩展提供了便利。JWT具备以下几个优点:
因json的通用性,所以JWT是可以进行跨语言
JWT可以在自身存储一些其他业务逻辑所必要的非敏感信息
便于传输,jwt的构成非常简单,字节占用很小,所以它是非常便于传输的
它不需要在服务端保存会话信息,所以它非常适合应用在前后端分离的项目上
使用JWT进行鉴权的工作流程如下(重点):
JWT是由三段信息构成的(头部、载荷、签名),将这三部分使用.
连接在一起就组成了JWT字符串,形如:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImp0aSI6IjNmMmc1N2E5MmFhIn0.eyJpYXQiOjE1NTk1Mjk1MjksImlzcyI6Imh0dHA6XC9cL3d3dy5weWcuY29tIiwiYXVkIjoiaHR0cDpcL1wvd3d3LnB5Zy5jb20iLCJuYmYiOjE1NTk1Mjk1MjgsImV4cCI6MTU1OTUzMzEyOSwianRpIjoiM2YyZzU3YTkyYWEiLCJ1c2VyX2lkIjoxfQ.4BaThL6_TbIMBGLIWZgpnoDQ-JlAjzbiK3y3BcvNiGI
其中:
一个完整的头部就像下面的JSON:
{
'typ': 'JWT',
'alg': 'HS256'
}
然后将头部进行base64加密/编码(该加密是可以对称解密的),这就得到了jwt的第一部分。
定义一个payload:
{
"sub": "1234567890",
"name": "John",
"admin": true
}
依旧进行base64加密,这就得到了jwt的第二部分。
例如:
var encodedString = base64UrlEncode(header) + '.' + base64UrlEncode(payload);
var signature = HMACSHA256(encodedString, 'secret');
这样就得到了jwt的第三部分。
最终将三部分信息通过.
进行连接就得到了最终的jwt字符串。
需要注意的是
- secret是保存在服务器端的
- jwt的签发生成也是在服务器端的
- secret是用来进行jwt的签发和jwt的验证
所以,secret它就是服务端的私钥,在任何场景都不应该泄露出去。一旦其他人(包括客户端的用户)得知这个secret,那就意味着他们可以自我签发jwt,接口就没有安全性可言了。