API网关示例图
什么是API网关?
API 网关(API Gateway)是 API 托管服务,提供 API 的完整生命周期管理,包括创建、维护、发布、运行、下线等。您可使用 API Gateway 封装自身业务,将您的数据、业务逻辑或功能安全可靠的开放出来,用以实现自身系统集成、以及与合作伙伴的业务连接。
API网关,其实就是一个服务器,它封装了系统的所有业务,为不同的客户端(Web,App等)提供一系列的特定的API。当然了,它还可以提供身份验证、监控、负载均衡、缓存、请求分片与管理、静态响应处理等功能。
前面有一篇文章讲过了腾讯云无服务器云函数实践,里面提到了怎么用函数来实现无服务器的架构,而API网关正是如何调用这些函数API的关键。
API网关原理
API网关调用
还是以腾讯云API网关为例,其它家的功能也类似。
首先,API网关中可以创建一到多个服务(service)。其次,每一个服务(Service)中又可以创建多个API被调用。那么,一个具体的API是什么样呢?
简单来说用过Spring MVC的人可以将API当成是一个Controller里面实现的某一个Request方法。
一个API由前端和后端两部分配置完成:
前端:主要用来配置请求的类型,方法,路径,参数等,相当于RequestMapping注解的功能。后端:主要用来配置API的实现方法,http,mock和腾讯云无服务器云函数,相当于被RequestMapping标记过的Java方法。通过这些基本的原理,我们应该知道了,API网关主要就是如何去配置服务和API的前后端,至于它怎么做服务,怎么负载均衡,这些都是由API网关的提供者来做。
关于配置,你还需要了解:
CORS:是否跨域访问,默认情况下,API网关都是跨域访问的。鉴权类型:所谓鉴权,也就是身份验证,即你提供的API在什么情况下可以被调用,毕竟API网关是按流量收费的。API网关身份验证
身份验证流程图
身份验证,也就是你通过API网关来调用API的时候,必须传入合适的数字签名以验证请求的合法性。
腾讯云API网关的签名格式为:
Authorization: hmac id="secret_id", algorithm="hmac-sha1", headers="date source", signature="Base64(HMAC-SHA1(signing_str, secret_key))"也就是说,在请求的header里要加一个key为Authorization,值为hmac以及后面那一串的签名字符串。
hmac:这是固定内容,用来标识算法。id:在API网关的密钥中生成的密钥名。algorithm:加密算法的类型,目前只hmac-sha1。headers:参与签名计算的 header,按实际计算时的顺序排列,headers里面必须要包含date或是x-date里面的一个,用于表示请求构造的时间,且为GMT格式(如:Fri, 09 Oct 2022 00:00:00 GMT)。signature:计算签名后得到的签名。具体的实现方法如下:
一, 得到当前系统时间,并转为GMT格式。
let nowDate = new Date(); let dateTime = nowDate.toGMTString();二,将headers拼串。
比如我们参与签名的header有2个:X-Date和Source,则拼串的代码为:
let signStr = "x-date: " + dateTime + "\n" + "source: " + source;拼好的串格式如下,注意换行(用ASCII的换行符\n)
X-Date:Fri, 09 Oct 2022 00:00:00 GMTSource:MyApp三,生成签名
将上一步中拼好的串使用Base64(HMAC-SHA1(signing_str, secret_key))签名。
let sign = CryptoJS.HmacSHA1(word, SECRET_KEY); return CryptoJS.enc.Base64.stringify(sign);四,生成Authorization header
将第二步生成的header和第三步生成的签名以及secretId一起拼成Authorization header。
五,发送请求
将第二步中用到的headers和生成的签名全部放到request的头信息里
X-Date:Fri, 09 Oct 2022 00:00:00 GMTSource:MyAppAuthorization: hmac id="secret_id", algorithm="hmac-sha1", headers="x-date source", signature="Base64(HMAC-SHA1(signing_str, secret_key))"