扯 dan
应用程序接口(英语:Application Programming Interface,简称:API),又称为应用编程接口,就是软件系统不同组成部分衔接的约定。由于近年来软件的规模日益庞大,常常需要把复杂的系统划分成小的组成部分,编程接口的设计十分重要。程序设计的实践中,编程接口的设计首先要使软件系统的职责得到合理划分。良好的接口设计可以降低系统各部分的相互依赖,提高组成单元的内聚性,降低组成单元间的耦合程度,从而提高系统的维护性和扩展性。
以上是 WiKi 对 API 的描述,日常开发中笔者通常以 API(接口) 来狭义地指代 Web API(Web Service)。当然这种现象可能只存在于移动互联网行业里(甚至 Only me ?有其它称呼可以留言哦),毕竟人家做硬件也会提供 API 。反正下文中笔者以 API 来指代 Web API ,少按 5 次键盘 🕵。
聊聊 60 分的 Web API ,这个 Topic 其实也是笔者 YY 出来的,实在是墨水有限。为何只是“聊聊 60 分的”,笔者认怂,自认只了解 60 分的水平(实际 30?及格分总要给吧 😳),希望大 🐂🐂 能不吝指导一二。接下来笔者会先简单描述下了解的三种 API 类型,然后再写下对于 60 分 API 应该具有的“素质”。
正文
API 风格
笔者了解到的 API 协议/架构风格主要有三种 —— RPC & SOAP & REST。 其中对于 RPC 和 SOAP 协议了解不够深入,下文着重描述 REST。
RPC
RPC,Remote Procedure Call 是一种计算机编程协议,该协议允许一套计算机调用另一台计算机上的子程序。RPC 定义了结构化的 Request 和 Response,以 GET 、POST 作为主要请求方法。请求数据格式可以是 XML,也支持更轻量的 JSON。
// XML RPC Request
<?xml version = "1.0"?>
<methodCall>
<methodName>getUserName</methodName>
<params>
<param>
<value>
<id>40</id>
</value>
</param>
</params>
</methodCall>
// XML RPC Response
<?xml version = "1.0"?>
<methodResponse>
<params>
<param>
<value>
<string>KentonYu</string>
</value>
</param>
</params>
</methodResponse>
SOAP
SOAP,Simple Object Access Protocol 是 Web Service 交换数据的一种协议,基于 XML-RPC 进行优化修改。它不仅支持 HTTP/HTTPS,还支持 SMTP 协议。它比 XML-RPC 更强大,但是数据格式只支持 XML。
SOAP XML 请求格式
REST
REST,Representational State Transfer(表述性状态转移)是一种架构风格,而不是协议。它是 Roy Thomas Fielding 博士于 2000 年在他的博士论文 "Architectural Styles and the Design of Network-based Software Architectures" 中提出来的,但是在 5 年后才开始受到关注。REST 通常基于 HTTP,URI 以及 JSON、XML 等协议和标准实现。当 REST 风格应用在 API 上时,我们称之为 RESTful API。
REST 并没有具体的规范,它只是一种风格。何为风格?提供一系列约束,但是不强制性要求必须满足这些约束。
REST 架构风格的形成,主要遵循了以下几点:
- 关注点分离;
- 可见性、可靠性和可伸缩性;
- 网络性能、效率;
- 统一接口;
总得来说,REST 是为了让 Web 服务更加高效、可靠、通用。
相对于 RPC(面向动作)、SOAP(消息机制),REST 是面向资源。资源,可以是服务器数据库的一张表,一张图片,或者说更加抽象的东西(当然这个东西要便于客户端开发理解)。
它主要是从以下三个方面来标识资源:
- 直观简短描述性的 URI;
- 传输的资源格式(JSON,XML,HTML.etc.);
-
对资源的操作,一般通过 HTTP 的一系列请求方法来表示;
HTTP 请求方法在 RESTful API 中的典型应用
那么 RESTful API 具体长什么样子?接下来我们就来看看 Github 的 API 设计,它是遵循 REST 风格的。
Github API 获取用户邮箱地址
这就是一个简单的遵循 REST 的 API,使用 HTTP 的 GET 方法指出是读取服务器资源,通过 URI “/user/emails” 来定位到具体的资源。REST 是面向资源的,因此在设计 URI 时是不会出现类似 “getEmails” 这样的动词。响应结果通过状态码(Status Code)来标识,具体响应数据通过 JSON 格式传输,当然也可以使用 XML 格式,甚至 HTML。
Github API 添加用户邮箱地址增加用户邮箱地址,采用 POST 请求方法,URI 仍旧是 “/user/emails”,因为这两个 API 操作的资源都是 Emails,因此 URI 是一致的。它们通过使用的请求方法(GET、POST、PUT、DELETE .etc.)来区分不同的动作。
小结
以上简略地描述了下 RPC、SOAP、REST 的概念,它们三者的目的是一致的 —— 作为客户端和服务端沟通桥梁。但是它们之间也是各有特点,比如 RPC 面向动作,SOAP 以消息作为通讯机制,REST 则面向资源。在实际开发的技术选型中,了解这三种的优劣势,在其中权衡,选择最高效、最适合的技术方案即可。当然,技术思想都是在不断发展进步的,后起之秀 REST 综合指数一定是比 RPC/SOAP 更具优势,它更适合一个新产品、新公司的技术选型,因为 REST 紧密贴合 HTTP,扩展性和兼容性更强,并且通过描述性的 URI 调用,客户端开发效率更高。
60 分 API 的素质
API 的一致性
一致性,大致可以分为两类:风格一致性和数据一致性。
风格一致性可能对于优化 API 的性能来说起不到实质性的作用,但是它的确可以提高团队的开发效率。如果一套 API 保持一致的风格,并且正确使用自描述性的命名,将会很大程度上提高 API 使用者的开发效率以及降低后续的维护成本。为了保持风格一致性团队必须有一份 API 规范文档来约束,这是必要的。
数据一致性主要提现在 API 的幂等性上,HTTP 的请求方法中 GET 、PUT、DELETE 应该保证是幂等的 —— 相同条件下,多次请求不会产生副作用。
安全性
API 的安全性在整个开发过程中毋庸置疑是最重要的环节之一,一套没有安全性可言的 API 对于用户或老板来说都是不负责任的表现。因为 API 是数据和用户连接的桥梁,API 的安全性直接关系到用户信息的安全性以及整个应用的安全性。因此一个 60 分的 API 应该具有一定的自我保护能力。
-
数据合法性验证
记得学封装的概念时看到的一句话,大致意思是暴露的 API 都必须保证数据的合法性,因为你永远不知道调用者会传什么数据给你。对于 Web API 来讲,它更不可能知道调用者会是谁(iOS、Andriod、模拟请求工具、黑客.etc.),会传什么数据给你,因此对于每一个 API 都应该进行数据合法性验证。一次请求包括 URI QueryString、 Request Header、Body ,API 应该一步步的判定这些数据的合法性,它们之间应该是“与”的关系。
最基础的数据验证应该做到过滤无效(或不合常理)数据,比如 API 入参有一个 age(interger) 字段,当某个请求传入 -1 时,就应该将拒绝这次不合法的请求,因为 age 不可能存在负数。
做到以上这一步只能说保护了数据库不会被写入不符合预期的数据,但是也要考虑到一些数据符合我们的约定,但是它本身具有攻击性,比如脚本注入,SQL 注入等。这些常见的攻击手段都应该在这一环节屏蔽掉。 -
数据完整性验证
请求数据需要经过网络的传输才能到达服务器端,在这过程中,API 需要确保请求数据是否完整(相对于客户端发送请求时的数据)。比如从云盘下载文件时,如果你的文件在传输过程中丢了一些包,那么这个文件将不能打开,并且这次下载是无效的。因此 API 要确保每一次请求的数据都是完整的,这可以通过请求的参数生成一个 MD5 验证字符串,在服务端验证数据完整性。
传输过程中请求数据可能会丢包或者被修改,那么数据库中的数据也可能会被其它请求修改,因此修改数据库数据时要确保数据的完整性,当客户端使用和数据库不一致的数据时,应该拒绝这次请求。这可以通过使用 ETag(某个资源的一个唯一的版本号,也可以用来实现 Cache )来防止错误更新,使用 "If-Match" 头来提供客户端的 ETag,判断和服务器资源当前版本是否一致(当然高并发时会存在 A 请求正在准备写入数据库,而 B 刚进入 ETag 验证,并且恰好通过)。 -
API 访问控制
对于大多数应用,它的 API 一定是不想公开被其它人使用的,尤其是竞争对手。一套合格的 API 应该具有一个合理的访问控制。目前较为普遍的是使用 HMAC 验证,通过一个密钥对请求信息进行算法处理,生成一个摘要信息,然后服务端通过同样的密钥进行处理,比对摘要信息是否一致来确定是否是合法请求。通过 HMAC 可以防止不合法的请求,并且保证数据没有受到“中间人”攻击。
除了 HMAC,还有 OAuth、HTTP BASIC Auth 等访问控制手段,当然你也可以自定义一些逻辑算法,比如可以将请求参数按首字母排序,加上请求时间戳(请求的实时性,防止一个 Request 在不同时间里重复请求)利用 DES、3DES、AES 等对称加密算法进行加密,生成一个请求密钥,服务端通过相同的逻辑算法来比对请求密钥,从而实现访问控制。
访问控制可以很大程度上避免 DDOS 攻击,防止服务器资源被“榨干”。
API 日志收集
API 应该收集每个请求的到达时间,处理时间,请求数据,响应数据,请求客户端信息等。日志的收集,有助于解决一些 bug,对于一些 API 的性能优化,以及运营人员的分析等。
丰富的 API 文档
一份丰富的 API 文档可以让客户端开发变的更加容易。把容易留给别人,那你就是佛祖,否则你就是人渣。文档中应该包含对所有 API 的一些通用描述,每个 API 都应该对应有 URI,请求头、参数,响应数据等,当然最好附带一个接口调试工具。这部分应该是服务端开发最头疼的事情了,每个 API 都要对应维护一份文档,但是目前有很多工具可以通过维护代码里的注释生成文档,从而减少开发的工作量,比如 swagger 、apidoc .etc.。
其它
除此之外,API 还应该支持例如 API 版本管理、事件处理回调等,具有良好的扩展性、后期可维护性等。针对安全性较高的 API,可以考虑使用 HTTPS ,在你的 API 外面再套一层壳。
结束语
笔者只是通过查阅相关的文献、博客等,总结了以上的内容。如有补充,欢迎留言。希望后续开发中,能将这些一一应用,码一套 60 分的 API。
网友评论