自建一个简易的OpenAPI网关

标签: 语言 Go 系统设计 | 发表时间:2020-07-16 03:30 | 作者:
出处:https://www.fanhaobai.com/

网关(API Gateway)是请求流量的唯一入口,可以适配各类渠道和业务,处理各种协议接入、路由与报文转换、同步异步调用等,来管理 API 接口和进行请求流量控制,在微服务架构中,网关尤为重要。

预览图

背景

当然,现在已有很多开源软件,如 KongGraviteeZuul

这些开源网关固然功能齐全,但对于我们业务来说,有点太重了,我们有部分定制化需求,为此我们自建了一个轻量级的 OpenAPI 网关,主要供第三方渠道对接使用。

简介

功能特性

接口鉴权

  • 请求 5s 自动过期
  • 参数 md5 签名
  • 模块粒度的权限控制

接口版本控制

  • 支持转发到不同服务
  • 支持转发到同一个服务不同接口

事件回调

  • 事件订阅
  • 最大重试 3 次
  • 重试时间采用衰减策略(30s、60s、180s)

系统架构

从第三方请求 API 链路来说,第三方渠道通过 HTTP 协议请求 OpenAPI 网关,网关再将请求转发到对应的内部服务端口,这些端口层通过 gRPC 调用请求到服务层,处理完请求后依次返回。

从事件回调请求链路来说,服务层通过 HTTP 协议发起事件回调请求到 OpenAPI 网关,并立即返回成功。OpenAPI 网关异步完成第三方渠道事件回调请求。

系统架构

实现

网关配置

由于网关存在内部服务和第三方渠道配置,更为了实现配置的热更新,我们采用了 ETCD 存储配置,存储格式为 JSON。

配置分类

配置分为以下 3 类:

  • 第三方 AppId 配置
  • 内外 API 映射关系
  • 内部服务地址

配置结构

a、第三方 AppId 配置

AppId配置

b、内部服务地址

内部服务地址

c、内外 API 映射关系

API映射关系

配置更新

利用 ETCD 的 watch 监听,可以轻易实现配置的热更新。

配置热更新

当然也还是需要主动拉取配置的情况,如重启服务的时候。

拉取热更新

API 接口

第三方调用 API 接口的时序,大致如下:

API调用时序

参数格式

为了简化对接流程,我们统一了 API 接口的请求参数格式。请求方式支持 POST 或者 GET。

API调用时序

接口签名

签名采用 md5 加密方式,算法可描述为:

1、将参数 p、m、a、t、v、ak、secret 的值按顺序拼接,得到字符串;
2、md5 第 1 步的字符串并截取前 16 位, 得到新字符串;
3、将第 2 步的字符串转化为小写,即为签名;

PHP 版的请求,如下:

$appId = 'app id';     
$appSecret = 'app secret';
$api = 'api method';

// 业务参数
$businessParams = [
'orderId' => '123123132',
];

$time = time();
$params = [
'p' => json_encode($businessParams),
'm' => 'inquiry',
'a' => $api,
't' => $time,
'v' => 1,
'ak' => $appId,
];

$signStr = implode('', array_values($params)) . $appSecret;
$sign = strtolower(substr(md5($signStr), 0, 16));

$params['s'] = $sign;

接口版本控制

不同的接口版本,可以转发请求到不同的服务,或同一个服务的不同接口。

接口版本控制

事件回调

通过事件回调机制,第三方可以订阅自己关注的事件。

接口版本控制

对接接入

渠道接入

只需要配置第三方 AppId 信息,包括 secret、回调地址、模块权限。

渠道AppId配置

即,需要在 ETCD 执行如下操作:

$ etcdctl set /openapi/app/baidu '{     
"Id": "baidu",
"Secret": "00cf2dcbf8fb6e73bc8de50a8c64880f",
"Modules": {
"inquiry": {
"module": "inquiry",
"CallBack": "http://www.baidu.com"
}
}
}'

服务接入

a、配置内部服务地址

配置内部服务地址

即,需要在 ETCD 执行如下操作:

$ etcdctl set /openapi/backend/form_openapi '{     
"type": "form",
"Url": "http://med-ih-openapi.app.svc.cluster.local"
}'

b、配置内外 API 映射关系

配置内部服务地址

同样,需要在 ETCD 执行如下操作:

$ etcdctl set /openapi/api/inquiry/createMedicine.v2 '{     
"Module": "inquiry",
"Method": "createMedicine",
"Backend": "form_openapi",
"ApiParams": {
"path": "inquiry/medicine-clinic/create"
}
}'

c、接入事件回调

接入服务也需要按照第三方接入方式,并申请 AppId。回调业务参数约定为:

配置内部服务地址

Golang 版本的接入,如下:

const (     
AppId = "__inquiry"
AppSecret = "xxxxxxxxxx"
Version = "1"
)

type CallbackReq struct {
TargetAppId string //目标APP Id
Module string //目标模块
Event string //事件
Params map[string]interface{} //参数
}

func generateData(req CallbackReq) map[string]string {
params, _ := json.Marshal(req.Params)
p := map[string]interface{}{
"ak": req.TargetAppId,
"m": req.Module,
"e": req.Event,
"p": string(params),
}

pStr, _ := json.Marshal(p)
postParams := map[string]string{
"p": string(pStr),
"m": "callback",
"a": "callback",
"t": fmt.Sprintf("%d", time.Now().Unix()),
"v": Version,
"ak": AppId,
}

postParams["s"] = sign(getSignData(postParams) + AppSecret)

return postParams
}

func getSignData(params map[string]string) string {
return strings.Join([]string{params["p"], params["m"], params["a"], params["t"], params["v"], params["ak"]}, "")
}

func sign(str string) string {
return strings.ToLower(utils.Md5(str)[0:16])
}

未来规划

  • 后台支持配置 AppId
  • 事件回调失败请求支持手动重试
  • 请求限流

相关 [建一 简易 openapi] 推荐:

自建一个简易的OpenAPI网关

- - FHB科学院
网关(API Gateway)是请求流量的唯一入口,可以适配各类渠道和业务,处理各种协议接入、路由与报文转换、同步异步调用等,来管理 API 接口和进行请求流量控制,在微服务架构中,网关尤为重要. 当然,现在已有很多开源软件,如 Kong、 Gravitee、 Zuul. 这些开源网关固然功能齐全,但对于我们业务来说,有点太重了,我们有部分定制化需求,为此我们自建了一个轻量级的 OpenAPI 网关,主要供第三方渠道对接使用.

openApi-auth

- - 陶陶技术博客
在与第三方系统做接口对接时,往往需要考虑接口的安全性问题,本文主要分享几个常见的系统之间做接口对接时的认证方案. 例如订单下单后通过 延时任务 对接 物流系统 这种 异步 的场景,都是属于系统与系统之间的相互交互,不存在用户操作;所以认证时需要的不是用户凭证而是系统凭证,通常包括 app_id 与 app_secrect.

构建一个简易 JavaScript 数据访问层

- Anew - IBM developerWorks 中国 : 文档库
本文逐步描述完成以下任务的全过程:在 PHP 中构建一个针对后端的数据库访问包装器并将其连接到用户界面层中的一个 JavaScript 访问包装器.

简易榨汁器

- Richard - 设计|生活|发现新鲜
现在各种各样的自动化家电,绝对让你成为懒人中的懒人. 其实,有时候自己亲自动手别有一番趣味,试试这款简易榨汁器吧. 看看你制作出来的口感和机器制作出来的是否一样呢. 「设计,生活,发现新鲜」在新浪微博,更即时地获读更新,更直接地交流沟通. © 设计|生活|发现新鲜 | 原文链接 | 投稿 ! | 新浪微博 | 逛逛我们的在线商店.

简易垃圾桶

- Zoe - 玩意儿
Jonliow 设计了一款简易的垃圾桶,外形就像是一个倒立的凳子,不过它却又很强的灵活性,可以放置各种大小的垃圾袋,比一般的垃圾桶更容易清洗,不过不能倒汤汁类的,否则垃圾袋有破洞就麻烦了. 本文原始链接:http://www.cngadget.cn/simple-trash.html. 让办公室的垃圾也为你增加乐趣.

git 使用简易指南

- -
下载 git Windows 版. 下载 git Linux 版. 创建新文件夹,打开,然后执行 . 执行如下命令以创建一个本地仓库的克隆版本:. 如果是远端服务器上的仓库,你的命令会是这个样子:. 你的本地仓库由 git 维护的三棵“树”组成. 第一个是你的 工作目录,它持有实际文件;第二个是 缓存区(Index),它像个缓存区域,临时保存你的改动;最后是 HEAD,指向你最近一次提交后的结果.

简易的python web服务器用途

- Ruby - Erlang非业余研究
原创文章,转载请注明: 转载自Erlang非业余研究. 本文链接地址: 简易的python web服务器用途. 我们在工作中经常会需要看下报表,如tsung的统计报表或者lcov的覆盖情况,这些报表通常为了方便都会作成html格式的. 我们可以把这些html网页打包拉回去用浏览器慢慢看,但是每次都要打包,拉数据非常麻烦.

廉价简易蒸汽发动机

- han - 果壳网 guokr.com - 果壳网
DIYer:liam2317 制作时间:一天 制作难度:★★★☆☆ GEEK指数:★★★★☆. 1   介绍:廉价简易蒸汽发动机 1.1   想法. 9   第八步:大功告成 9.1   活塞. 1   介绍:廉价简易蒸汽发动机. 我最近看了一段视频,有人制作了一台小型蒸汽发动机驱动的遥控小船,当时我就hold不住了.

Node.js 的简易web服务器

- bingo - 走走停停看看
网上关于Node.js的介绍已经铺天盖地了,但我就没找到一个简单的web服务器给我做测试用. 实际上Node.js只需要一个exe文件和一个js文件就可以搭建服务器了,用来随便测试页面之类的用起来比nginx还方便. 只可用于http服务,没有更多功能的js文件. 1,先去 http://nodejs.org/下载最新的Node.js可执行的exe文件.

响应式设计简易指南

- - Jing
我们想让我们的网站通过响应用户的行为、设备的屏幕大小和屏幕方向,从而在所有设备上都能用. 截止2013年,有成千上万种不同的设备在浏览网页,所以我们不可能设计出适应所有屏幕大小的网页. 相反,我们必须得采用一种更加流畅的方式去设计. 最近一个比较火的词叫移动优先. 它的意思是,先为移动端设计样式,然后再根据需求去优化更大屏幕的样式.