Skip to content
本页索引

API Proxy

API Proxy 是 KMS核心概念 之一,是 KMS 提供的接口访问代理服务,将实际需要访问的 web 请求映射到 KMS 的特殊路由下,然后通过 KMS 后端服务中转网络请求。同时还有另外两种不同的 Proxy 模式以应对不同的场景诉求。

Proxy vs. CORS

由于浏览器的安全限制,从浏览器发出的大部分网络请求,会被限制在当前页面所在的域名和端口上。如果请求的目标地址存在 协议 域名 端口 的任意差异,就可能导致请求失败,这时需要进行跨域资源共享的设置。

跨域资源共享通常有两个办法来处理:

  1. 所有跨域请求改道经服务端中转:在服务器端发出请求是不受限制的,经过服务器中转(也可以同时加签名)后就可以轻松解决前端请求跨域的问题,KMS 生产环境所采用的 API Proxy 就是这种策略;

  2. 请求的服务器通过 HTTP Head 设置 CORS 信息,允许浏览器直接发出请求。这种策略也不复杂,只需要额外响应可能的 OPTIONS 请求,以及设置一组特定的 Head 头信息即可,这里是详细资料;API Proxy 的本地调试模式就是采用这种方式;

    通常只需要设置以下 Head 头信息:

    JavaScript
    // koa2 中间件
    async function corsMiddleware(ctx, next) {
        const origin = ctx.headers.origin
        if (!origin) {
            await next()
            return
        }
        // 如果请求的 head 中有 origin 信息,则表示是跨域请求
        // 检查请求头中的 origin 信息,如果允许,则写入响应的 head 信息,值保持不变
        // 因为现代浏览器都默认启用了严格模式的跨域策略,设置 * 的方式已经无效
        ctx.set("Access-Control-Allow-Origin", origin)
        // 写入跨域请求的缓存有效期,即在设定的时间内,不再重复检查跨域预检,单位秒
        ctx.set("Access-Control-Max-Age", 8 * 60 * 60)
        // 允许的跨域请求方法,按照实际情况返回即可
        ctx.set("Access-Control-Allow-Methods", "GET,HEAD,PUT,POST,DELETE,PATCH")
        // 以下这个设置很关键,需要从请求头中获取有哪些自定义 head 信息,并写入到 响应的 head 中
        // 否则,自定义的 head 信息不被明确允许,也会导致跨域请求失败
        ctx.set("Access-Control-Allow-Headers", ctx.headers["access-control-request-headers"])
        // 如果当前请求是预检请求,则不需要处理具体的业务逻辑,设置完毕 head 信息后就可以结束了
        if (ctx.request.method === "OPTIONS") {
            ctx.body = "ok"
            return
        }
        await next()
    }
    go
    // gin 中间件
    func CorsMiddleware(c *gin.Context) {
    	origin := c.Request.Header.Get("Origin")
        if origin == "" {
            c.Next()
            return
        }
        // 如果请求的 head 中有 origin 信息,则表示是跨域请求
        // 检查请求头中的 origin 信息,如果允许,则写入响应的 head 信息,值保持不变
        // 因为现代浏览器都默认启用了严格模式的跨域策略,设置 * 的方式已经无效
        c.Header("Access-Control-Allow-Origin", origin)
        // 写入跨域请求的缓存有效期,即在设定的时间内,不再重复检查跨域预检,单位秒
        c.Header("Access-Control-Max-Age", "28800")
        // 允许的跨域请求方法,按照实际情况返回即可
        c.Header("Access-Control-Allow-Methods", "GET,HEAD,PUT,POST,DELETE,PATCH")
        // 以下这个设置很关键,需要从请求头中获取有哪些自定义 head 信息,并写入到 响应的 head 中
        // 否则,自定义的 head 信息不被明确允许,也会导致跨域请求失败
        c.Header("Access-Control-Allow-Headers", c.Request.Header.Get("Access-Control-Request-Headers"))
        // 如果当前请求是预检请求,则不需要处理具体的业务逻辑,设置完毕 head 信息后就可以结束了
        if c.Request.Method == "OPTIONS" {
            c.AbortWithStatus(200)
            return
        }
        c.Next()
    }

    注意

    这种方式在 KMS 使用场景中,只会发生在 本地调试 模式下,生产环境不应该允许这些接口接受跨域请求。所以,请设置一个开关,并只在本地开发调试模式下,允许上述跨域设置代码生效。

Proxy Payload 数据

经过 KMS 中转代理的请求,KMS 会追加签名信息到 HTTP Head 中。实际 API 的处理程序可以验证这些签名信息来鉴定请求的合法性。这些签名信息称为 Proxy Payload,具体包括 系统 Payload 和 自定义 Payload。

假设我们在 KMS 配置如下:

上述配置中,KMS 将会把自身的路由 /a0/* 分配至给 https://test.com/api/*,在表单和视图的网络请求中,url地址可以填写:/a0/userlist,则该请求会被 KMS 后端服务接收,然后转给 https://test.com/api/userlist 进行处理,同时会在请求的 Head 中追加以下字段和内容(Payload 数据,以 x-kms- 前缀的为系统 Payload):

yaml
x-kms-user 		操作者信息,全小写的邮箱地址
x-kms-username 	操作者姓名,从 SSO 获取的姓名,可能是中文/英文/邮箱
x-kms-stamp 	服务器当前时间的毫秒时间戳
x-kms-appid 	系统登记的 AppID,通常是一个数字,也可能为空字符串
x-kms-project 	当前项目名称
x-kms-sign 		签名数据,可选三种签名方式
x-api-token		自定义 payload 字段(可选)

上述 x-kms-sign 签名数据,有三种可选签名方式:

  • sha256(user + stamp + token)
  • sha256(user + project + stamp + token)
  • sha256(user + project + appid + stamp + token)

重要提示

参与签名计算的 token 是可选的,如果设置,则长度不能小于31位,并且 API Proxy 保存后将无法再次查看和修改token。请在生成 token 后及时保存到合适位置。

API Proxy 限制

API Proxy 设置的业务服务器 API 域名,有一个限制:不能是 localhost,ip 地址,KMS 自身域名。因为上述设置在 KMS 服务器端是没有实际意义的。需要 本地调试 或者 IP直连,可以参考后续章节内容。

同时,业务服务器 API 协议,支持 httphttps。通常的一个建议是:

只在代理 KMS 同一个集群内部的应用时使用 http 协议,代理集群外的应用一律使用 https。

API Proxy 环境分组

为了应对实际开发中多环境的需求,KMS 支持设置不同的 API Proxy 分组。如果您有相应权限,您将在 API Proxy 页面看到如下功能按钮:环境分组,默认情况下添加的 API Proxy 是生产环境,如果需要添加不同环境下的 API Proxy,则需要通过环境分组功能添加环境标记:

一个项目最多添加 5 组自定义环境,加上默认的 生产环境 和 local 环境,一个项目可以支持最多 7 套环境。

添加分组后,将会看到不同环境的添加按钮:

不同环境中的路由前缀是独立统计的,这就意味这你可以在 dev 环境中配置同样一个 a0 的配置,但可以采用不同的 url 或者 Payload 数据,在菜单管理界面,可以一键切换 API Proxy 环境:

Local Proxy 本地调试

为了方便调试 API Proxy,KMS 支持 Local Proxy 功能。此功能需要在 API Proxy 界面勾选 开启本地调试 后起效。有以下注意事项: 【请先设置跨域

  • 本地调试原理:将原本需要服务端转发的请求直接在浏览器中发出以达到调试本地服务器接口的目的;
  • 请先处理跨域配置:由于请求从浏览器直接发出,势必造成跨域访问,请先在本地服务器添加跨域白名单,参考资料
  • 签名数据无法模拟:出于安全和实现机制考虑,本地调试 API Proxy 将无法实现等价的签名功能,ajax 和 upload 将追加固定的示例签名数据,其他格式(jsonp/script/download)将无法追加任何签名信息;
  • 仅对当前浏览器生效:所有调试的配置将存储在当前浏览器内,所有 API Proxy 调试功能仅仅对当前浏览器有效;
  • 并非所有功能都支持调试:除了 API Proxy 之外,其他功能,比如表单和视图,都没有调试功能,请在更新那些数据时留意这些不同;

注意

“开启本地调试” 功能,不仅仅开启了 API Proxy 本地调试,也将同时开启 Webhook 调试功能

Direct Proxy 直连代理

通常情况下,API Proxy 搭配 Local Proxy 可以完成开发调试和上线所需要的功能,但有一个场景不能完成业务诉求:

  • 业务服务器只能在某个局域网内访问,KMS 所在的集群无法触达这个局域网

这个情况通常在项目初期的某个时期存在,为此 KMS 开发了 Direct Proxy 功能,此功能默认不开启,需要管理员在项目配置的功能配置中开启后生效。

  • 直连代理原理:在浏览器端直接发出代理请求,而不经过服务器中转,适用于尚未部署公网的服务;
  • 请先处理跨域配置:由于请求从浏览器直接发出,势必造成跨域访问,请先在目标服务器添加跨域白名单,参考资料
  • 不支持签名:出于安全和实现机制考虑,Direct Proxy 将无法实现安全的签名功能,所有调用都是直接请求;

三种模式对比

API ProxyLocal ProxyDirect Proxy
请求在服务端发出✔️--
ajax / upload 支持签名✔️固定demo数据-
jsonp / script / download 支持签名✔️--
业务 API 不需要处理跨域✔️--
功能可见性所有用户仅当前浏览器所有用户
配置生效优先级
安全性-
适用场景生产环境开发调试项目初期调试

优先级

配置三种模式的前缀是独立的,比如可以分别设置三个 /a0/ 的 API Proxy,Local Proxy 以及 Direct Proxy,其中 本地调试优先级最高,其次是 Direct Proxy,最后是 API Proxy。