RestFul风格
Roy Fielding博士在2000年他的博士论文中提出REST(Representational State Transfer)风格的软件架构模式。
符合Rest原则的架构可以成为RestFul
REST API不应该依赖于任何通信协议,尽管要成功映射到某个协议可能会依赖于元数据的可用性、所选的方法等。
REST API不应该包含对通信协议的任何改动,除非是补充或确定标准协议中未规定的部分。
REST API应该将大部分的描述工作放在定义用于表示资源和驱动应用状态的媒体类型上,或定义现有标准媒体类型的扩展关系名和(或)支持超文本的标记。
REST API绝不应该定义一个固定的资源名或层次结构(客户端和服务器之间的明显耦合)。
REST API永远也不应该有那些会影响客户端的“类型化”资源。
REST API不应该要求有先验知识(prior knowledge),除了初始URI(书签)和适合目标用户的一组标准化的媒体类型(即,它能被任何潜在使用该API的客户端理解)。
HTTP
请求行
请求方法 GET,POST,DELETE,PUT, PATCH(X-HTTP-Method-Override _Method)
首部 标准制定的首部,控制缓存,控制连接,请求协商
实体
请求报文和响应报文都包含有首部字段,首部字段按照类别可以分为:通用首部,请求首部,响应首部,实体首部
通用首部,可以出现在请求报文首部中,也可以出现在响应报文首部中,如upgrade,connection,cache-controll,pragma,via,date,trailer,transfer-encoding
请求首部是请求报文中特有的,不出现在响应报文中,按照请求首部的性质,可以将请求首部分为信息性首部,Accept首部,条件请求首部,安全请求首部,代理请求首部
信息性首部包含客户端请求的一些信息: host,refer等
Accept首部是和服务器协商,目的是改善友好的交互:Accept,Accept-language,Accept-encoding
条件请求首部,是请求实体时的某一条件:if-match,if-none-match,if-modified-since,if-unmodified-since,range,if-range
安全请求首部,增加安全的首部,cookie,cookie2
代理请求首部,和代理相关的一些首部:max-forward
响应首部是响应报文中特有的,不出现在请求报文中,按照响应首部的性质,可以将响应首部分为信息性首部,协商首部,安全响应首部.
信息性首部会有服务器的一些信息:server,age等
协商首部,提供更好的资源:
安全响应首部:set-cookie,set-cookie2
实体首部是描述实体的信息,一般随实体出现而出现,
实体首部按照不同类型可以分为实体信息性首部,内容首部,实体缓存首部
实体信息性首部:location,allow
内容首部:content-length,content-type,content-Language,content-encoding,content-location,content-md5,content-range,content-base
实体缓存首部:etag,expires,last-modified
首部和实体直接是使用两个CRLF进行分隔。
实体包含了需要传输的内容信息。HTTP协议传输的内容包含所有的一切,视频,图片,文档,HTML等等。
资源
网络上的所有事务都抽象为资源
每个资源有一个唯一标识符
看url是否能准确定位到一个资源数据
如何美化API
遵守设计规范明确的内容
没有设计规范明确的内容遵守相关事实标准
方便更改设计的WEP API
面向大范围公开的LSUDs,尽可能具备通用性并易于理解和使用
SSKDs面向终端用户:移动应用
发布以后的API
一:作为平台发布的api
二:移动API,不同的版本app可能使用不同格式api
三:内部发布的API
优化的方式
:尽量不修改发布的API
:支持同时提供多个版本的API
指定版本号
1)在URL中指定版本号:
http://www.xxx.com.cn/v2/iit/declare
http://www.xxx.com.cn/2/iit/declare
添加v字母显示的更加一目了然,容易理解
如何确定版本号
1.2.3 1.2.3.4
使用语义化版本控制
版本信息由点号链接的3个数字组成,分别表示主版本号,次版本号,补丁版本号,并有如下规则:如果软件的API没有发生变更,只是修正了部分bug,则增加补丁版本编号
在对软件进行向下兼容的变更或废除某些特定的功能,增加次版本编号
在对软件进行不向下兼容的变更时,增加主版本编号。
多个版本有坏处
维护成本高
用户容易混淆
尽量不升级版本 升级补丁版本号
非常少见的设计
使用日期来描述API的版本号
2)在查询字符串中加入版本信息
(比较1,2方式,更加倾向于哪一种)
3)使用媒体类型/私有首部添加版本信息
停用API
预先准备好停止服务的规范
一:提前通知用户
二:按步骤启用新接口/停用旧接口
三:在条款中写明支持期限。(6个月,12个月)
公开API相关的准备
提供API文档:API的使用方式
提供SDK:提供便捷的操作
网页调试API:用户检查api有什么功能,访问方式是否正确,已经API返回的数据结构是怎么样
API设计校验
URI
1)简单易懂
2)只有小写字母
3)使用合适的HTTP方法
4)相同的单词和大部分的api含义是否一致
API 端点设计思想
容易记忆,URI包含的功能一目了然(即使文档中对URI进行了详细的说明,也不能说可以对URI可以随意设计,开发人员不会仔细阅读文档。如果可以在没有频繁阅读文档的情况可以开发,还能减少因没有阅读文档而引发的BUG。URI应该体现功能,数据结构和含义)
短小便于输入的URI(冗长的URL一般有无用,重复的内容,做精简的时候可以删去)
人可以读懂的URI (如果从URI中知道该URI做什么,可以不用每次去查看文档,提高工作效率。也会减少开发人员因为难以理解而错误访问URI的情况)
不要轻易使用缩写形式 http://api.example.com/p/u
使用API常用的英语单词
尽可能避免拼写错误
单词的复数形式和过去式形式容易混淆没有大小写混合的URI (说驼峰的形式不好并不代表使用下划线或者横线就比较好,而是这样的设计本身就存在问题)
修改方便的URI(是指方便的将一个URI修改为另一个URI,前提是结构不变化的情况,如使用商品ID去查询商品)
不会暴露服务器架构端的URI (不应该暴露服务器端是如何运作的)比如/cgi-bin/. .php
规则统一的URI
friends?id=100
friend/100/message
fridens/100
friend/100/message
不要使用需要编码的字符
使用连接符‘-’
URI是否可以添加search
反对 因为search表示的是搜索是动词,不应该放在表示资源的URI中
如果API功能表示的是搜索用途,而不是用来获取所有的列表信息,那么加上search可以更加容易理解。 这些特别是在以搜索为主要目的的在线服务中。
域名的考虑
域名是URL的一部分,作为对外提供的接口服务,可以考虑在域名中加入api的字段
比如:api.xxxx.com. xxxxapis.com
参数的设计
获取数据量和数据位置的参数
使用相对位置
使用 limit offset
page pageSize
使用绝对位置
使用id的位置
使用日期的条件
使用过滤的参数
全文匹配
不要指定具体的字段
精确匹配
模糊匹配
是否可以把查询参数放在路径里面
用来表示唯一资源所需要的信息(比如说ID信息,用来表示唯一的,比较适合放在路径里)
是否可以省略 (像分页信息和过滤的参数即使省略也可以指定默认值)
响应数据
设计优美的响应数据以及怎样让显影数据易于程序处理
通信过程中发送,接收的数据量越少越好
数据结构
使用JSON(XML)
只有出现更加易用的数据格式才能取代JSON
(不是对外开放的API,不用考虑支持其他数据格式)
JSONP 将JSON传给浏览器的方式,(也有作为跨域请求的方案)(如果不提供不应该支持,作为避免同源策略的手段,但同时可能导致不安全JSON劫持)
数据内部的结构
尽可能减少请求的次数,但也避免返回过多的内容
让客户选择响应的内容 接口指定返回的字段名
* 封装是否有必要,封装请求相关信息,比如错误信息,错误码,,但是如果是HTTP,那么这个协议返回值的状态码就可以表示是否处理成功
* 数据是否应该扁平化(经可能的使用扁平化,但是有些情况下使用层级形式更好)
* 序列和对象(是否需要将序列封装为对象)
各个数据的格式
数据的名称 (蛇形法,驼峰,没有特定要求使用哪一种,但是要求在系统中使用同一种规范)
描述性别的数据 (保持统一很重要,一个地方使用sex 其他地方也用sex)
sex 一般用数值来表示性别表示生理上的区分
gender 大多数用字符串表示性别,社会文化意义上的性别
* 日期的格式
如果使用时间戳 需要注意的是时区的问题,在不同的时区用时间戳生成的对象是不用的日期
如果用的是年-月-日 这样自定义的格式,不会跟着时区变化,相对固定。
* 大整数
因为不用的系统和编程语言对大整数的处理可能会有差异(比如JS对大整数的处理会有误差),所以在设计大整数的时候推荐使用字符串格式
错误信息
通过状态码表示错误信息
错误信息 (详细错误信息,错误信息链接等)
* 维护和状态码
api不可用的时候(服务发布,系统部署,不过这样的操作成本高,可用性降低,一般采用不停机发布) (返回特定的错误码,或者503服务占不可用,并且指定首部Retry-After时间后重试)
* 返回不明确的消息
尽管我们消息提供需要做到精确,但是有些场景下不需要提供精确消息,比如登录的时候用户名和密码校验结果只需要返回相同的错误。不要提示密码错误或者用户名错误。
认证
OAuth1.0 OAuth2.0(2012.10公布的标准化,适用场景广,不会去使用OAuth1.0)
授权模式
授权码模式(authorization code)
简化模式(implicit)
密码模式(resource owner password credentials)
客户端模式(client credentials)(无需用户授权即可得到信息,比如访问公开的信息,也要客户端认证的情况下)
认证信息的传输
首部
请求体
查询字符串
认证更新
如果认证token到期需要去更新tonken,使用refreshtoken去获取信息的access token。这是授权的时候返回,如果没有则需要从新登录进行验证
其他考虑
性能,体验综合考虑,可以灵活变动
比如一个API需要整合多个API的请求,以提高效率
给予客户的考虑易于使用的端点和响应数据结构
编排层,在客户端和服务器API之前增加一层编排层,可以将多个api融合成一个,或者做不同客户端的适配等处理。
api公开后,api的使用方式就完全交给用户来决定,用户可能会以不曾想过的方式使用api
安全
信息流加密 SSL TLS
信息加密 DES AES
应用的不安全
交互的不安全:SQL注入,输出值转义不完全(http首部的转移,邮件首部转移字符),
会话机制不安全:XSS(自动执行用户输入的脚本),CSRF(跨站点请求伪造)
安全等级不够:强制浏览应用环境的不安全:
系统环境,如账号执行权限,隐藏端口,网络环境的不安全:
有危害的中间代理:监听传输的报文, 修改报文,
协议的不安全:SSL剥离
不安全的客户端:DOS攻击
Rest LEVEL3
使用HTTP
引入资源的概念
引入HTTP动词
引入HATEOAS
请求返回后续操作的API
每个返回的API带有媒体类型(比如人员详情 application/vnd.companyname.user.detail.v1+json),客户端根据这些媒体类型就知道怎么处理。
优点
只要知道入口,就能遍历所有API
节省从变更到发布的周期。
缺点
返回数据量会变大
api设计变得复杂
服务端和客户端都需要清楚设计的规范,难度比较大
这个概念确实存在着这些优点,但是在实际中比较难以推广