Kong侦听四个端口的请求,默认情况是:
8000
:此端口是Kong用来监听来自客户端的HTTP
请求的,并将此请求转发到您的上游服务。这也是本教程中最主要用到的端口。
8443
:此端口是Kong监听HTTP的请求的端口。该端口具有与8000
端口类似的行为,但是它只监听HTTPS
的请求,并不会产生转发行为。可以通过配置文件来禁用此端口。
8001
:用于管理员对KONG进行配置的端口。
8444
:用于管理员监听HTTPS
请求的端口。
在本文中,我们将介绍Kong的路由功能,并详细说明8000
端口上的客户端请求如何根据header
、URI
或HTTP
被代理到配置中的上游服务。
基础术语
API
:指Kong的API实例。您可以通过管理员身份配置您的API。
Plugin
:他指的是Kong的“插件”,它们是在代理生命周期中运行的业务逻辑。可以通过管理员身份进行全局配置,也可针对每个API进行分别配置。
Client
:指向Kong的代理端口发出请求的下游客户,即第三方客户端。
Upstream service
:指的是位于Kong后面的您自己的API服务,客户端请求被转发的最终目的地。nginx中的上游服务器。
概述
从整体上来看,Kong侦听其配置的代理端口上的HTTP
请求(默认为8000
),并识别正在请求的是哪个上游服务,然后运行在该API上的配置插件(如果没有则不执行),并将上游的HTTP请求转发到您自己的API服务。
当客户端向代理端口发出请求时,Kong将根据API在KONG里的配置情况,来决定将请求传入到哪个上游服务中。 您可以在KONG里对每个API添加许多属性,但是有三个是必须要配置的,他们是hosts
、uris
和methods
。如果KONG无法确定API请求的上游服务地址,则会返回一下内容:
HTTP/1.1 404 Not Found
Content-Type: application/json
Server: kong/<x.x.x>
{
"message": "no API found with those values"
}
回忆下:如何向KONG添加一个API
在之前的添加一个API的指南中,有学习过如何使用8001
端口,在KONG服务中添加一个API的操作:
$ curl -i -X POST http://localhost:8001/apis/ \
-d 'name=my-api' \
-d 'upstream_url=http://my-api.com' \
-d 'hosts=example.com' \
-d 'uris=/my-api' \
-d 'methods=GET,HEAD'
HTTP/1.1 201 Created...
该代码表示用户成功在Kong里注册一个名为my-api
的API,可通过访问http://example.com
发送请求。它还指定了一些HTTP请求的属性,但请注意,这里有且只有一个HOST
,URIS
和METHODS
属性。当完成此配置后,以后所有的符合此host
、uris
和methods
的请求,都将由KONG来代理过滤转发。Kong是一个透明的代理,它会将请求转发给您的上游服务,除了添加诸如Connection
之类的各种标题。
转发功能
现在我们来讨论一下,一个HTTP请求是如何与API配置属性(如host
、uris
、methods
)相匹配的。需要注意的是,这三个字段(h、u、m
)都是可选的,但至少要有一个被指定。对于客户端请求与API的匹配:
· 请求必须包含所有已配置的字段
· 请求中的字段值必须与至少一个已配置的值相匹配(尽管字段配置接受一个或多个值,请求只需要考虑匹配其中之一)
让我们来看几个例子。请看如下一个API配置:
{
"name": "my-api",
"upstream_url": "http://my-api.com",
"hosts": ["example.com", "service.com"],
"uris": ["/foo", "/bar"],
"methods": ["GET"]
}
与该API相匹配的一些请求可能是:
GET /foo
HTTP/1.1
Host: example.com
GET /bar
HTTP/1.1
Host: service.com
GET /foo/hello/world
HTTP/1.1
Host: example.com
以上的三个请求都满足API定义中设置的条件。但是,以下的几个请求则与配置的条件不匹配:
GET / HTTP/1.1
Host: example.com
POST /foo HTTP/1.1
Host: example.com
GET /foo
HTTP/1.1Host: foo.com
以上的三个请求只满足两个配置条件。第一个请求的URI
不匹配,第二个请求的HTTP方法不匹配,第三个请求的Host
头不匹配。
现在我们了解了hosts
、uris
、methods
是如何一起工作的。下面我们来逐个了解他们是如何单独工作的。
请求的HOST头
基于HOST头发送请求,是通过KONG发送请求的最直接的一种方式,这也是HOST头的基本用法之一。KONG使通过HOST访问API实体的流程更加简便快捷。HOSTS 接受多种参数,当使用管理员API进行请求时,需要将每个参数间用逗号分隔开来配置:
$ curl -i -X POST http://localhost:8001/apis/ \
-d 'name=my-api' \
-d 'upstream_url=http://test-api.com' \
-d 'hosts=test-api.com,demo.com,service.com'
HTTP/1.1 201 Created
...
此时,客户端可使用 hosts=test-api.com, demo.com, service.com
中的任意一个HOST头对 my-api
进行访问,但不能缺省HOST的值。
使用通配符查找主机名
为了使代理更灵活,KONG允许使用通配符来配置HOSTS。通配符允许任何满足条件的HOST头对API实体进行访问。在配置通配符时,只允许在HOST的最左或最右配置一个星号*
,例如:
*.example.com
:允许类似于 a.example.com
或 a.b.example.com
等形式的HOST头访问。
example.*
:允许类似于 example.a
或 example.b.cn
等形式的HOST头访问。
一个完整的例子:
{
"name": "test-api",
"upstream_url": "http://test-api.com",
"hosts": ["*.example.com", "service.com"]
}
匹配的HOST头请求类似于一下几种,但不限于一下的例子中的形式:
GET / HTTP/1.1
Host: an.example.com
GET / HTTP/1.1
Host: service.com
preserve_host属性
当启用代理时,KONG默认将API的upstream_url
的值配置为上游服务主机的 host
。preserve_host
提供一个boolean
值,对KONG的这个行为进行限制。例如,当使用preserve_host
的默认值进行配置时,API的配置信息大致为:
{
"name": "my-api",
"upstream_url": "http://my-api.com",
"hosts":
[
"service.com"
],
}
此时,客户端发送的请求信息格式大致为:
GET / HTTP/1.1
Host: service.com
KONG会从API的upstream_url
中提取HOST
值,在做代理时,会向上游服务发送类似的请求:
GET / HTTP/1.1
Host: my-api.com
然而,当管理员在配置API时,明确指定了preserver_host=true时:
{
"name": "my-api",
"upstream_url": "http://my-api.com",
"hosts":
[
"service.com"
],
"preserve_host": true
}
并假设客户端发送了相同的请求:
GET / HTTP/1.1Host: service.com
KONG将会保留客户端发送来的HOST值,在做代理时,会向上游服务发送以下的请求:
GET / HTTP/1.1Host: service.com
请求URI
KONG将请求转发给上游服务的另一种方式,是通过配置uris
属性来指定请求的URI
值。uris
可以配置多个值,此时客户端在进行请求时,必须选择uris中的一个值作为请求的前缀。
例如,如果API的配置为:
{
"name": "my-api",
"upstream_url": "http://my-api.com",
"uris": ["/service", "/hello/world"]
}
以下的几种请求方式都可以对此API进行访问:
GET /service HTTP/1.1
Host: my-api.com
GET /service/resource?param=value HTTP/1.1
Host: my-api.com
GET /hello/world/resource HTTP/1.1
Host: anything.com
以上几种方式在进行请求时,KONG侦测到他们的前缀与API的uris
属性值是匹配的,所以这些请求是可用的。
当uris
属性配置好后,在进行请求时,KONG首先会取最长的uris
值对URI
进行匹配筛选,如果未匹配,然后才会取次长度的uris
值进行匹配,依次类推,直到匹配成功为止或拒绝访问。譬如上面的例子里,在发送请求时,KONG首先会取 /hello/world
与请求uri进行匹配,如果未成功,才会继续取 /service
继续匹配工作。
strip_uri
属性
在配置API的uris时,如果你希望隐藏上游服务的真实uri,并以另外的一种URI提供给客户端时,通过简单的配置API的strip_uri属性就可以实现。例如:
{
"name": "my-api",
"upstream_url": "http://my-api.com",
"uris": ["/service"],
"strip_uri": true
}
启用strip_uri
属性来指示Kong在代理此API时,在上游请求的URI
中不应包含匹配的URI
前缀。针对上面的API配置,当客户端发送请求时
GET /service/path/to/resource HTTP/1.1
Host:
KONG代理到上游服务的真实uri为(此时的uri不包含uris中配置的内容)
GET /path/to/resource HTTP/1.1
Host: my-api.com
HTTP请求方法
从KONG 0.10版本开始,可以通过配置API的methods
属性来指定客户端的请求。默认情况下,无论HTTP请求方式如何,Kong都会将请求将其代理到API的。但是,当配置methods
属性后,只有HTTP请求方式匹配时才会被KONG代理。methods
属性可以配置多个值:
{
"name": "api-1",
"upstream_url": "http://my-api.com",
"methods": ["GET", "HEAD"]
}
以下的两种HTTP请求方式都可以被代理
GET / HTTP/1.1
Host:
HEAD /resource HTTP/1.1
Host:
但是不会匹配POST或DELETE等其他的请求方式。配置此属性,可以更细粒度的管理你的API。
代理的优先级
一个API可以通过配置hosts
、uris
和methods
属性定义匹配规则。对于Kong来说,只有当所有的字段都匹配时,才会进行转发。然而,KONG允许两个或更多的API拥有相同的配置。此时,就涉及到请求的优先级问题了。
匹配优先级原则是:在评估请求时,Kong会首先与匹配规则最多的API进行匹配[en](when evaluating a request, Kong will first try to match the APIs with the most rules.)。例如有两个API的配置如下
{
"name": "api-1",
"upstream_url": "http://my-api.com",
"hosts": ["example.com"]
},
{
"name": "api-2",
"upstream_url": "http://my-api-2.com",
"hosts": ["example.com"],
"methods": ["POST"]
}
api-2
比api-1
多了一个methods
配置,所以KONG会最先将请求与api-2
进行匹配。通过此配置,我们就能避免在请求api-2时,错误的转发到api-1
。
此时,这个请求会被转发到api-1
:
GET / HTTP/1.1Host: example.com
而这个请求,会被转发到api-2
:
POST / HTTP/1.1Host: example.com
以此类推,如果一个api同时配置了hosts
、methods
、uris
,则这个API会最先与请求进行匹配,他的优先级会是三个中最高的。
代理行为
上述内容详细讲述了KONG将请求代理到上游服务的代理规则。下面我们将详细说明,在KONG将请求转发到上游服务的这段时间内实际发生的一些事。
负载平衡
从KONG 1.10 版本开始,Kong继承实现了负载平衡的功能,可以将转发的请求分发到多个上游服务实例。在 Kong 0.10之前,一般情况下,Kong会将代理的请求转发到指定的upstream_url
上,如果想实现服务的负载平衡,需要额外的工具来完成。您可以通过查阅负载平衡相关资料,找到更多有关向API添加负载平衡的信息。
插件扩展
使用者可以通过plugins
来自定义扩展插件,并将插件应用到request
/response
的生命周期中。插件可以在您的生产环境中对代理行为进行多种操作。通过对插件进行配置,可以将插件应进行全局应用或针对个别API应用。如果对给定的某个或某些API应用了一个插件或多个插件,则在代理请求到上游服务前,会首先执行API的匹配,匹配成功后再执行定义的插件,当插件执行完后,如果满足天剑,才会将请求最终代理到上游服务中去。这里包含了插件的访问时段的概念,具体参考插件开发配置相关资料。
代理或请求超时
当KONG将所有的代理逻辑,包括API验证和插件等,都处理完后,才会将请求代理到上游服务。这些是通过Nginx
的代理模块来实现的。从KONG 0.10开始,可以通过配置以下三个API属性来定义连接超时时间:
upstream_connect_timeout
: 定义同上游服务建立连接的超时时间,单位是毫秒,默认值为60000
.
upstream_send_timeout
: 定义两个连续向上游服务发送的写入操作的超时时间,单位是毫秒,默认值为60000
.
upstream_read_timeout
: 定义两个连续向上游服务发送读取操作的超时时间,单位是毫秒,默认值为60000
.
在使用HTTP/1.1
时,KONG会默认添加以下请求头信息:
HOST
:<上游服务的host
>
Connection:keep-alive
: 允许重复使用上游连接
X-REAL-IP:<$proxy_add_x_forwarded_for>
: 参见 nginx_http_proxy_module
.
X-Forwarded-Proto:<protocol>
: protocol
是客户端使用的协议名
其他的请求头都按默认配置添加。
当使用WebSocket
时,会有例外发生。如果发生,KONG允许通过以下请求头对协议进行升级:
Connection
:Upgrade
Upgrade
:WebSocket
Response
Kong接收上游服务的响应,并以流式方式将其发回下游客户端。此时,Kong将执行添加到该特定API的后续插件,并且这些插件继承了header_filter
子句。当所有继承了header_filter
的插件执行完后,以下的几种头信息将返回给客户端:
Via
:kong/x.x.x
KONG的版本信息,x.x.x是他的版本号。
Kong-Proxy-Latency
:<latency>
,其中 latency
表示Kong接收来自客户端的请求并将请求发送到上游服务所消耗的时间值(毫秒)。
Kong-Upstream-Latency
:<latency>
,其中 latency 表示Kong等待上游服务响应的第一个字节所消耗的时间数(毫秒)。
当headers发送到客户端后,Kong将执行此API上已注册的、继承了body_filter
的插件。body_filter
将上游返回的数据成功处理后,然后再发送给客户端。
配置一个fallback API
默认情况下,当向KONG发送请求时,如果请求失败,KONG会返回 HTTP 404
,API not found
等信息。为了避免这种情况的发生,我们可以通过配置 fallback API
实现自定义 异常\错误
信息。
下面是一个例子:
{
"name": "root-fallback",
"upstream_url": "http://www.error.page",
"uris": ["/"]
}
观察此配置中的uris
,会发现,此处配置/
可以适配所有的请求,根据uris
的匹配规则,每个请求都会首先匹配最长的uri,依次递减。所以当所有的uri
都不匹配时,请求会自动转发到这里配置的上有服务中去,因此而实现了自定义 异常\错误
信息。
配置API的SSL
Kong提供了一种在每个连接的基础上动态提供SSL证书
的方法。从0.10
版本开始,SSL插件
已被删除,SSL证书
由内核直接处理,并可通过Admin API
进行配置。你的客户端HTTP库必须支持SNI
Server Name Indication扩展以确保SSL
可用。
SSL证书
由Kong Admin API
的两个资源处理:
· /certificates
存储您的密钥和证书。
· /snis
将注册的证书与服务器名称指示相关联。
以下是为给定的API配置SSL证书
的方法:
首先,通过Admin API上传SSL证书和密钥
:
$ curl -i -X POST http://localhost:8001/certificates \
-F "cert=@/path/to/cert.pem" \
-F "key=@/path/to/cert.key" \
-F "snis=ssl-example.com,other-ssl-example.com"
HTTP/1.1 201 Created
...
snis
是加密参数,直接插入SNI
并将上传的证书与之相关联。
您现在必须在Kong内注册以下API。为方便起见,我们将使用Host头将请求转发到此API:
$ curl -i -X POST http://localhost:8001/apis \
-d "name=ssl-api" \
-d "upstream_url=http://my-api.com" \
-d "hosts=ssl-example.com,other-ssl-example.com"
HTTP/1.1 201 Created
...
好了,现在你可以向KONG发送HTTPs请求了:
$ curl -i https://localhost:8443/ \
-H "Host: ssl-example.com"
HTTP/1.1 200 OK...
https_only
参数:
如果你希望仅通过HTTPS
提供API,可以通过启用其https_only
属性来实现:
$ curl -i -X POST http://localhost:8001/apis \
-d "name=ssl-only-api" \
-d "upstream_url=http://example.com" \
-d "hosts=my-api.com" \
-d "https_only=true"
HTTP/1.1 201 Created
...
这样配置后,KONG将拒绝代理非HTTPS
的请求。如果此时使用HTTP请求
来访问这个API,KONG会提示用户需要将客户端升级到HTTPS
:
$ curl -i http://localhost:8000 \
-H "Host: my-api.com"
HTTP/1.1 426
Content-Type: application/json; charset=utf-8
Transfer-Encoding: chunked
Connection: Upgrade
Upgrade: TLS/1.2, HTTP/1.1
Server: kong/x.x.x
{"message":"Please use HTTPS protocol"}
http_if_terminated
参数:
当API被锁定在HTTPS请求
时,如果你想在请求头信息中添加X-Forwarded-Proto
,只要为API配置http_if_terminated
属性即可:
$ curl -i -X PATCH http://localhost:8001/apis/ssl-only-api \
-d "http_if_terminated=true"
HTTP/1.1 200 OK
...
并且我们使用X-Forwarded-Proto
(假设它来自可信任的客户端)发出请求:
$ curl -i http://localhost:8000 \
-H "Host: my-api.com" \
-H "X-Forwarded-Proto: https"
HTTP/1.1 200 OK
...
Kong现在代理了这个请求,因为它假定你的体系结构的先前组件已经实现了SSL
。
代理WebSocket
由于KONG的底层实现了Nginx
,所以他也支持WebSocket
。如果你希望在客户端和KONG之间建议一个WebSocket
连接,那么你必须首先建立一个WebSocket
握手。这个通过HTTP Upgrade
机制完成。这个可以通过客户端对KONG进行操作,例如:
GET / HTTP/1.1
Connection: Upgrade
Host: my-websocket-api.com
Upgrade: WebSocket
此时,KONG会将Connection
和Upgrade
两个请求头转发到上游服务中去。
小结
通过本指南,希望你了解了Kong的底层代理相关的知识,从API的uris
匹配,到如何使用WebSocket
协议、为API配置SSL
。如果想了解更多的相关知识,请参考Nginx
的负载平衡相关内容。
网友评论