DESIGN 怎样设计一个合理的 HTTP API (一)
这个附件的幻灯片是我最近给团队分享关于设计 HTTP API 的时候,结合 这篇 和我们团队历史上的一些错误,总结出来一些适合内部的经验。
简介.这次分享主要关注以下几部分:
HTTP + JSON API 的最佳实践
更关注 API 使用和概念上的一致性
这些使用上的经验,并不是最终的、唯一的解决方案
同时也无法处理任意环境中遇到的全部问题
同时还会举出一些 badcase,这些 badcase 一般是我负责的或者开发的服务中遇到的问题。
背景知识.在 HTTP API 实践中,涉及到了以下背景知识,可能需要了解
HTTP 尝试
JSON 规范
最好写过几个服务的 API
RESTful
Agenda.这个幻灯片,会从以下三个方面,沟通和讨论,在实现一个合理、易用的 API 需要关注的事项。
API 基础
发送请求
返回结果
API基础资源隔离(Separate Concerns)
安全连接
服务端版本号
Etags & Cache
Request IDs
Ranges
Separate Concerns在规划一个 API 的时候,应该将不同的“资源”,分布到不同的 URI 下,不要将不同的资源放置到同一个 URI 下面进行操作。
下面是一个好的例子:
/v1.0/gossip/mine
/v1.0/gossip/user/uid
/v1.0/gossip/detail/gossip_id
/v1.0/user/invite
我也在工作中,遇到过一些做的不好的 API:
host:prot/?qt=cd2
host:port/?qt=s
这个不好的例子在于,将所有对资源的操作,都放到了 GET 参数中,这样最直接的坏处就是,会对线上查找日志造成影响(因为你不能确保 qt 会出现在?后面,然后如果有多个字段需要 grep,那就需要 bash 达人出手才行了; 去线上 grep 日志简直就是``pain-in-the-ass‘‘)。
除此之外,在代码上,后一种方式也会造成不小的混乱。比如在这个例子中, 前者的入口是这样写的:
1 app = Flask(__name__) 2 app.register_blueprint(user_api, 3 url_prefix=‘/v1.0/user‘) 4 app.register_blueprint(gossip_api, 5 url_prefix=‘/v1.0/gossip‘) 6 app.register_blueprint(bigbro_api, 7 url_prefix=‘/v1.0/dd‘) 8 app.register_blueprint(util_api, 9 url_prefix=‘/‘) 10 app.run(host=‘0.0.0.0‘, port=port, debug=True)
而后者呢,一般是这样写的:
1 $qt = $_REQUEST[‘qt‘]; 2 if ($qt == ‘cd2‘) { 3 // xxx 4 } else if ($qt == ‘s‘) { 5 // xxx 6 }
安全连接一个 API,在安全方面,应该做到以下几点:
全部使用 TLS
关闭 web Server 的 80 端口
为非 TLS 请求返回``403 Forbidden‘‘
同样,尽量避免使用``重定向‘‘,因为客户端使用的库可能无法正常处理重定向、RD 可能会忽略重定向,多次重定向会增加服务都拿压力。
服务端版本号服务、客户端升级前后的兼容,一直是服务开发的人力黑洞。所以从服务的第一个版本开始,需要将版本更迭这件事考虑在内。
解决办法是在每一个请求中,增加当前使用协议的版本号。一个简单地方法是在 Header 中增加版本号,可以减少版本信息对 API 接口的干扰。
比如这样:
Accept: application/vnd.heroku+json; version=3
如果你不这样做,那么在你的服务运维一段时间之后,尤其是客户端已经发布出去但是后面发现了 bug,你的代码很可能是这样的:
1 if (isset($_REQUEST[‘cduss‘]) && 2 ($result[‘cdstat‘] == 0) && 3 (substr($param[‘os‘], 0, 6) == ‘iphone‘) && 4 ($param[‘sv‘] == ‘2.1.0‘)) 5 { 6 $rst[‘errorno‘] = -1; 7 }
ETags、Cache合理地使用 ETags,配合 Cache,可以同时减轻服务端、客户端的压力。这件事需要客户端和服务端的配合:
Server 为每一个返回的资源设置对应的 ETags
Client 需要合理使用 ETags(``If-None-Match‘‘)
Server 端需要响应请求头中的 Etags 信息
关于里面提到的 ETags、If-None-Match, 你自己放狗搜一下吧。
Request ID温馨提示: 本文由Jm博客推荐,转载请保留链接: https://www.jmwww.net/file/71520.html