HTTP-API-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'')。
除此之外,在代码上,后一种方式也会造成不小的混乱。比如在这个例子中, 前者的入口是这样写的:
app = Flask(__name__)
app.register_blueprint(user_api,
url_prefix='/v1.0/user')
app.register_blueprint(gossip_api,
url_prefix='/v1.0/gossip')
app.register_blueprint(bigbro_api,
url_prefix='/v1.0/dd')
app.register_blueprint(util_api,
url_prefix='/')
app.run(host='0.0.0.0', port=port, debug=True)
而后者呢,一般是这样写的:
$qt = $_REQUEST['qt'];
if ($qt == 'cd2') {
// xxx
} else if ($qt == 's') {
// xxx
}
安全连接
一个 API,在安全方面,应该做到以下几点:
- 全部使用 TLS
- 关闭 web Server 的 80 端口
- 为非 TLS 请求返回``403 Forbidden''
同样,尽量避免使用``重定向'',因为客户端使用的库可能无法正常处理重定向、RD 可能会忽略重定向,多次重定向会增加服务都拿压力。
服务端版本号
服务、客户端升级前后的兼容,一直是服务开发的人力黑洞。所以从服务的第一个版本开始,需要将版本更迭这件事考虑在内。
解决办法是在每一个请求中,增加当前使用协议的版本号。一个简单地方法是在 Header 中增加版本号,可以减少版本信息对 API 接口的干扰。
比如这样:
Accept: application/vnd.heroku+json; version=3
如果你不这样做,那么在你的服务运维一段时间之后,尤其是客户端已经发布出去但是后面发现了 bug,你的代码很可能是这样的:
if (isset($_REQUEST['cduss']) &&
($result['cdstat'] == 0) &&
(substr($param['os'], 0, 6) == 'iphone') &&
($param['sv'] == '2.1.0'))
{
$rst['errorno'] = -1;
}
ETags、Cache
合理地使用 ETags,配合 Cache,可以同时减轻服务端、客户端的压力。这件事需要客户端和服务端的配合:
- Server 为每一个返回的资源设置对应的 ETags
- Client 需要合理使用 ETags(``If-None-Match'')
- Server 端需要响应请求头中的 Etags 信息
关于里面提到的 ETags、If-None-Match, 你自己放狗搜一下吧。
Request ID
对服务涉及到很多上下游,还需要跨团队的API 来说, Request ID 是你在追查问题的法宝: 它通过一个统一的规则,将为请求分配的唯一 ID 增加在 HTTP 头中并向下游服务传递,像一条线一样,把整个服务流程上线串联起来,日后可以通过这个 ID 来分析请求执行的情况。
同时 Server 端也应该把 Request ID 增加在返回的结果中,这样客户端可以拿到它,会对调试提供极大的帮助。
Range
再也不要用 pg=x&num=y&order=uid 来进行分页、排序了,将这些字段统统放到Range 里面去:
- Client 发送 Range Header
- Server 返回中,需要增加``Next-Range'' Header
- 需要约定好``default-page-size'' 和 ``max-page-size''
你看到了,全部使用 Range 的话,客户端根本不需要自己拼凑请求,只需要把上一次 Server 返回的 ``Next-Range'' 再放回到请求头中,就可以完成“下一页”的操作了。
像这样:
curl -i -n -X GET https://api.heroku.com/apps \
-H ``Accept: application/vnd.heroku+json; version=3'' \
-H ``Range: name ..; order=desc,max=10;''
Accept: application/vnd.heroku+json; version=3
HTTP-API-DESIGN 怎样设计一个合理的 HTTP API (一)的更多相关文章
- HTTP-API-DESIGN 怎样设计一个合理的 HTTP API (二)
接上篇 HTTP-API-DESIGN 怎样设计一个合理的 HTTP API (一) 整个 ppt 可以去这里下载. 这一篇主要从服务端应该如何返回合理的返回值的角度,讨论如何设计一个合理的 HTTP ...
- 使用MATLAB 2019 App Design 工具设计一个 电子日记App
使用MATLAB 2019 App Design 工具设计一个 电子日记App1.1 前言:由于信号与系统课程需要,因此下载了MATLAB软件,加之对新款的执着追求,通过一些渠道,下载了MATLAB ...
- 如何设计一个亿级网关(API Gateway)?
1.背景 1.1 什么是API网关 API网关可以看做系统与外界联通的入口,我们可以在网关进行处理一些非业务逻辑的逻辑,比如权限验证,监控,缓存,请求路由等等. 1.2 为什么需要API网关 RPC协 ...
- 如何设计一个牛逼的API接口
在日常开发中,总会接触到各种接口.前后端数据传输接口,第三方业务平台接口.一个平台的前后端数据传输接口一般都会在内网环境下通信,而且会使用安全框架,所以安全性可以得到很好的保护.这篇文章重点讨论一下提 ...
- 设计一个高质量的API接口
参考网址:http://url.cn/5UaTeyv 前言 在设计接口时,有很多因素要考虑,如接口的业务定位,接口的安全性,接口的可扩展性.接口的稳定性.接口的跨域性.接口的协议规则.接口的路径规则. ...
- 如何设计一个restful风格的API
1.API接口应该尽量兼容之前的版本,在URL上应保留版本号,并同时兼容多个版本 2.每一个URI代表一个资源 3.请求方式要与http请求方式一致,GET(获取),POST(新增),PUT(更新全部 ...
- 如何设计一个优秀的API
如何设计一个优秀的API - 文章 - 伯乐在线 http://blog.jobbole.com/42317/ 如何设计一个优秀的API - 标点符 https://www.biaodianfu.co ...
- 如何设计一个良好的API接口?
沟通创造价值,分享带来快乐.这里是程序员阅读时间,每天和你分享读书心得,欢迎您每天和我一起精进.今天和大家一起讨论的话题是如何设计一个良好的API接口? 作者:梁桂钊 解读:张飞洪 挑战 API是软件 ...
- 如何架构一个合适的企业API网关
API Gateway(API GW / API 网关),顾名思义,是出现在系统边界上的一个面向API的.串行集中式的强管控服务,这里的边界是企业IT系统的边界,主要起到隔离外部访问与内部系统的作用. ...
随机推荐
- php 验证上传图片尺寸
getimagesize 函数 取得图像大小 (PHP 4, PHP 5) array getimagesize ( string filename [, array &imageinfo] ...
- 前端开发 - CSS - 总结
CSS:层叠样式表(Cascading Style Sheets) 1.css的特征2.css的引入3.选择器4.伪类选择器5.伪元素选择器6.字体样式 文本样式 背景属性7.盒模型 border m ...
- 4.2 - MySQL
一.表关系 请创建如下表,并创建相关约束 班级表:class 学生表:student cid caption grade_id sid sname gender class_id 1 一年一班 1 1 ...
- apt-get 报 The following signatures were invalid: KEYEXPIRED 错误
apt-get 原理: 参考:https://blog.csdn.net/a13526758473/article/details/79247478 apt对它所管理的每一个程序包都有一对公钥和私钥, ...
- linux下安装mysql(mariadb)
yum安装软件(官网很慢) yum install mariadb 发现版本如下,版本特别低,且安装包特别小, mariadb x86_64 :-.el7_5 base 8.9 M .我们可以配置ma ...
- ReferenceQueue
@Test public void strongReference() { Object referent = new Object(); /** * 通过赋值创建 StrongReference * ...
- 跨域问题session不一致问题的解决(前端和后台在不同的服务器)
场景:首先调用发送短信接口,然后调用注册接口,结果后台的session不一致获取不到之前验证码. 实质:每次ajax跨域访问都是新的session ,每次的sessionID都不一样 解决: pack ...
- Apache Lucene初探
讲解之前,先来分享一些资料 首先,学习任何一门新的亦或是旧的开源技术,百度其中一二是最简单的办法,先了解其中的大概,思想等等.这里就贡献一个讲解很到位的ppt 这是Lucene4.0的官网文档:htt ...
- NGS中的一些软件功能介绍
1.bowtie 短序列比对工具,blast也是短序列比对工具,速度快,结果易理解. 输入可以是fastq或者fasta文件. 生成比对结果文件sam格式的吧. 2.bwa 转自:https://ww ...
- oracle的字符集设置与乱码
oracle的字符集设置与乱码 字符集问题一直叫人头疼,究其原因还是不能完全明白其运作原理. 在整个运行环节中,字符集在3个环节中发挥作用: 1.软件在操作系统上运作时的对用户的显示,此时采用操作系统 ...