Restful规范

1、关于Restful

随着前后端分离越来越普遍,后端接口规范也就越来越重要了。一套良好的接口规范可以提升工作效率,减少沟通障碍。通常我们都会采用RestfulApi方式来提供接口,使用JSON来传输数据。

Restful是一种软件架构风格,不是标准。既然不是标准,可以遵守,也可以不遵守!!!

2、Api设计6要素

  • 资源路径(URI)

  • HTTP动词(Method)

  • 过滤信息(query-string)

  • 状态码(Status-code)

  • 错误信息(Error)

  • 返回结果(Result)
    Restful规范_第1张图片

3、Restful规范要求

在实际开发中,本着提高工作效率、降低沟通障碍的初衷,使用Restful规范去开发接口时,对于6要素有着以下的要求:

3.1、资源路径(URI)

资源:所有在服务器(电脑)保存的数据(如:音乐/视频/文章/个人信息…)都是服务器端资源.(项目中资源通常都是指的数据表的一条数据)

URI(Uniform Resource Identifier):统一资源标志符,包含URL和URN

URL(Uniform Resource Locator):统一资源定位符

URN(Uniform Resource Name):统一资源名

Restful规范_第2张图片
在HTTP协议中, URI的组成如下:

  • 接口通信协议

    • http
    • https
  • 接口域名

    • 最好是独立解析的域名,如www.xxx.com,域名是需要购买的
  • 端口号

    • http默认为80
    • https默认为443
  • 接口版本

    • 将版本信息放在URI中 http://www.xxx.com/v1
  • 请求路径

    • 网络中的任何东西都为资源,均使用名词表示(一般为复数形式),如针对用户模块请求路径可以为http://www.xxx.com/v1/users/1

3.2、HTTP动词(Method)

对于资源,一般有4个操作:CURD(增/删/改/查)

  • GET: 从服务器获取资源(一项或多项)(查)
  • POST: 在服务器新建一个资源(增)
  • PUT: 在服务器更新资源,服务器返回完整的属性(改)
  • DELETE: 从服务器删除资源(删)【假删,逻辑删除】

以新闻资源为例: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路径(路由)称之为资源路由

3.3、过滤信息(query-string)

通常也叫做请求参数或查询字符串(“?id=1&age=213”)。

3.4、状态码(Status-code)

成功发送的请求必有响应(响应可能没有响应体,但是状态码肯定有),每个响应都会有一个状态码。在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)- 服务端当前无法处理请求

3.5、错误信息(Error)

如果状态码是4xx或者5xx, 需要告诉客户端对应的错误信息。通常以Json格式返回,形式如下:

{
	'error': '错误信息',
    'code': '错误编号',
    'msg': '资源没找到',
    'message': 'xxxx',
    'text': 'xxxx',
    'reason': 'xxxxxx'
}

3.6、返回结果(Result)

针对不同的操作,服务需要返回的结果应该符合这样的规范:

  • 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名字要遵循见名知义

4、接口安全

前后端分离式开发需要进行数据交互,传输的数据被偷窥、被抓包、被伪造时有发生,那么如何设计一套比较安全的API接口方案呢?

并不是所有的接口都需要考虑安全的,有些接口是公开的,任何人只要知道地址都可以调用,对于一些项目中需要用户登录才能访问的接口才需要考虑安全问题。

一般解决的方案有以下几类:

  • token令牌认证(jwt)
  • AK(app key)&SK(secret key)【用户名&密码】
  • 时间戳超时验证+签名算法字符串
  • URL签名(算法,非对称算法)
  • 数据脱敏(防范数据库数据泄露)
  • HTTPS
    • 数字证书(防运营商)
  • IP黑/白名单(服务器层面的限制,apache、nginx)
  • oAuth2.0

关于JWT

Json web token(JWT),是基于token的鉴权机制,类似于http协议也是无状态的,它不需要在服务端去保留用户的认证信息或者会话信息,为应用的扩展提供了便利。JWT具备以下几个优点:

  • 因json的通用性,所以JWT是可以进行跨语言

  • JWT可以在自身存储一些其他业务逻辑所必要的非敏感信息

  • 便于传输,jwt的构成非常简单,字节占用很小,所以它是非常便于传输的

  • 它不需要在服务端保存会话信息,所以它非常适合应用在前后端分离的项目上

使用JWT进行鉴权的工作流程如下(重点):

  • 用户使用用户名密码来请求服务器
  • 服务器进行验证用户的信息(查数据库)
  • 服务器通过验证发送给用户一个token(令牌)
  • 客户端存储token(Vuex+localStorage),并在每次请求时附送上这个token值
  • 服务端验证token值,并返回数据

Restful规范_第3张图片
JWT是由三段信息构成的(头部、载荷、签名),将这三部分使用.连接在一起就组成了JWT字符串,形如:

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImp0aSI6IjNmMmc1N2E5MmFhIn0.eyJpYXQiOjE1NTk1Mjk1MjksImlzcyI6Imh0dHA6XC9cL3d3dy5weWcuY29tIiwiYXVkIjoiaHR0cDpcL1wvd3d3LnB5Zy5jb20iLCJuYmYiOjE1NTk1Mjk1MjgsImV4cCI6MTU1OTUzMzEyOSwianRpIjoiM2YyZzU3YTkyYWEiLCJ1c2VyX2lkIjoxfQ.4BaThL6_TbIMBGLIWZgpnoDQ-JlAjzbiK3y3BcvNiGI

其中:

  • 头部(header),包含了两(可以更多)部分信息,分别是类型的声明和所使用的加密算法。

一个完整的头部就像下面的JSON:

{
  'typ': 'JWT',
  'alg': 'HS256'
}

然后将头部进行base64加密/编码(该加密是可以对称解密的),这就得到了jwt的第一部分。

  • 载荷(payload),载荷就是存放有效信息的地方。这些有效信息包含三个部分
    • 标准中约定声明(建议但不强制)
    • 公共的声明
    • 私有的声明

定义一个payload:

{
  "sub": "1234567890",
  "name": "John",
  "admin": true
}

依旧进行base64加密,这就得到了jwt的第二部分。

  • 签名(signature),这个签证信息由三部分组成:
    • 经过base64编码后的
      • header
      • payload
    • secret(就是一个字符串,自己定义,值是什么无所谓)

例如:

var encodedString = base64UrlEncode(header) + '.' + base64UrlEncode(payload);
var signature = HMACSHA256(encodedString, 'secret');

这样就得到了jwt的第三部分。

最终将三部分信息通过.进行连接就得到了最终的jwt字符串。

需要注意的是

  • secret是保存在服务器端的
  • jwt的签发生成也是在服务器端的
  • secret是用来进行jwt的签发和jwt的验证

所以,secret它就是服务端的私钥,在任何场景都不应该泄露出去。一旦其他人(包括客户端的用户)得知这个secret,那就意味着他们可以自我签发jwt,接口就没有安全性可言了。

你可能感兴趣的:(node,restful,http,java,javascript,node.js)