条件路由

在介绍条件路由之前,让我们先了解一下请求在网关里的工作过程。当一个请求达到网关以后:

  1. 匹配端点(end-point)。如下图所示,我们定义各种入口,入口决定了一个请求被识别成哪一个API End Point
  2. 当End Point匹配成功以后,请求会以链状的通过各种设定的策略(Policy)。入下图红框所示。这里需要注意,有些Policy是可以终止请求的。比如“脚本(Script)”就可以通过return语句来返回请求,这样请求就不会到达后续的处理逻辑,包括不会到达上游服务。 Policy
  3. 当经过了所有的Policy之后,就进入了“条件路由(Routing)”环节。在Flomesh里,我们设计条件路由主要是满足如下的需求场景:对于一个API,可能会有多个“提供者(Provider)”,比如多个版本,或者多个地域的部署,针对不同的请求,我们会根据特征,把请求路由到不同的“提供者”。比如我们把一个“服务”部署在北京和上海两个数据中心,所以我们创建两个Provider,分别叫做BJ_AZ和SH_AZ;在请求到达以后,我们可以根据请求头中x-forward-for这里提供的IP,查询GeoIP库,转换成地理位置;对于请求来自SH的,转发到SH_AZ,其他的请求转发到BJ_AZ。类似的我们还可以根据各种不同的条件,包括请求的Header,甚至是请求BODY里某种特征,转发到特定的Provider。

演示案例

这里我们用一个简单的例子来看下如何实现条件路由。这个例子很简单,我们创建两个Provider,一个叫做honeypot,一个叫做real-server。当请求头中的User Agent是curl的时候,请求被转发到honeypot;否则转发到real server。

创建API和Providers

参考[“101反向代理”]配置一个API,名字叫做“103条件路由”,并且为这个API配置一个EndPoint -- 配置路径为/103routing; 再配置两个Service Provider,分别叫做HoneyPot和RealService。配置后如下图: 基础配置

配置条件路由

在API编辑页面,在“脚本”的标签页里,“启用脚本”,然后在编辑区输入如下的lua脚本:

if ngx.re.find(ngx.var.http_user_agent or '', 'curl', 'ai') then
    return 'HoneyPot'
else
    return 'RealServer'
end

这时候看起来是这样的: 条件路由

验证测试

这个时候,可以用不同的UA来做测试:

TC1: UA=curl

[root@localhost kong]# curl -vvvv http://localhost:8000/ok 
* About to connect() to localhost port 8000 (#0)
*   Trying ::1...
* 拒绝连接
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 8000 (#0)
> GET /ok HTTP/1.1
> User-Agent: curl/7.29.0
> Host: localhost:8000
> Accept: */*
> 
< HTTP/1.1 200 OK
< Content-Type: application/octet-stream
< Content-Length: 3
< Connection: keep-alive
< Date: Sun, 15 Dec 2019 09:43:58 GMT
< Set-Cookie: __cfduid=db83ba283dbb2c6c67a9031d49adee8371576403037; expires=Tue, 14-Jan-20 09:43:57 GMT; path=/; domain=.flomesh.cn; HttpOnly
< Last-Modified: Mon, 09 Sep 2019 13:41:56 GMT
< ETag: "5d7656a4-3"
< Accept-Ranges: bytes
< CF-Cache-Status: DYNAMIC
< Server: cloudflare
< CF-RAY: 545779eb5da6eb3d-LAX
< 
ok
* Connection #0 to host localhost left intact

TC2: UA=caishu

[root@localhost kong]# curl -vvvv http://localhost:8000/ok -H "User-Agent: caishu"
* About to connect() to localhost port 8000 (#0)
*   Trying ::1...
* 拒绝连接
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 8000 (#0)
> GET /ok HTTP/1.1
> Host: localhost:8000
> Accept: */*
> User-Agent: caishu
> 
< HTTP/1.1 200 OK
< Content-Type: application/octet-stream
< Content-Length: 3
< Connection: keep-alive
< Server: nginx/1.16.1
< Date: Sun, 15 Dec 2019 09:43:50 GMT
< Last-Modified: Sun, 15 Dec 2019 08:48:43 GMT
< ETag: "5df5f36b-3"
< Accept-Ranges: bytes
< 
ng
* Connection #0 to host localhost left intact

测试结论

从测试可以看出,当ua是不同的值的时候,请求被路由到了不同的Provider。