本篇博客主要记录了我在使用 GraphQL 和 Apache APISIX 搭配过程中遇到的很多问题。纯属个人产出,有不对的地方还望指出。
基础命令
路由规则配置
# basic Apache APISIX config
curl http://127.0.0.1:9080/apisix/admin/routes/11 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -i -d '
{
"methods": ["POST"],
"uri": "/graphql",
"vars": [
["graphql_operation", "==", "query"],
["graphql_name", "==", "getRepo"],
["graphql_root_fields", "has", "owner"]
],
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
反馈
一般在我之前的OpenResty中正常配置好1980服务器后,我配置APISIX路由正确之后会返回如下的信息
HTTP/1.1 200 OK
Date: Fri, 04 Feb 2022 22:00:03 GMT
Content-Type: application/json
Transfer-Encoding: chunked
Connection: keep-alive
Server: APISIX/2.10.3
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: *
Access-Control-Max-Age: 3600
{"action":"set","node":{"value":{"update_time":1644012003,"create_time":1642620298,"methods":["POST"],"uri":"\/graphql","priority":0,"upstream":{"hash_on":"vars","scheme":"http","type":"roundrobin","nodes":{"127.0.0.1:1980":1},"pass_host":"pass"},"vars":[["graphql_operation","==","query"],["graphql_name","==","getRepo"],["graphql_root_fields","has","owner"]],"id":"11","status":1},"key":"\/apisix\/routes\/11"}}
简单请求
# basic request
curl -H 'content-type: application/graphql' -X POST http://127.0.0.1:9080/graphql -d '
query getRepo {
owner {
name
}
repo {
created
}
}'
反馈
当APISIX路由配置正确之后,请求一个基础请求
---Headers
x-real-ip:127.0.0.1
host:127.0.0.1:9080
x-forwarded-proto:http
x-forwarded-host:127.0.0.1
x-forwarded-port:9080
content-length:82
content-type:application/x-www-form-urlencoded
accept:*/*
user-agent:curl/7.29.0
x-forwarded-for:127.0.0.1
---Args
---URI
/graphql
---Service Node
Centos-port: 1980
进阶操作
感谢大佬时刻
这边感谢一下我泽轩大佬,谢谢他给我提出的宝贵意见。非常感谢!
体现 roundrobin 均衡策略
简单记一下逻辑,其实就是不断配置APISIX的路由规则
这边 upstream
里配置了分别架设在 OpenResty 上端口为 1980 和 1981 的两个 node
curl http://127.0.0.1:9080/apisix/admin/routes/11 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -i -d '
{
"methods": ["POST"],
"uri": "/graphql",
"vars": [
["graphql_operation", "==", "query"],
["graphql_name", "==", "getRepo"],
["graphql_root_fields", "has", "owner"]
],
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1,
"127.0.0.1:1981": 1
}
}
}'
两个服务器的权重都设置为 1,一个等级,这里边 2 的权重大于 1。
然后分别发出请求的话,会按照顺序,1 > 2 > 1 > 2 > 1......的顺序得到 upstream
服务器的响应。
根据 graphql_name 匹配 upstream 服务器
错误示范
这一串是给第一个 upstream 服务器配置 graphql_name 为getRepo111
curl http://127.0.0.1:9080/apisix/admin/routes/11 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -i -d '
{
"methods": ["POST"],
"uri": "/graphql",
"vars": [
["graphql_operation", "==", "query"],
["graphql_name", "==", "getRepo111"],
["graphql_root_fields", "has", "owner"]
],
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
第二个 upstream 服务器配置 graphql_name 为 getRepo222
curl http://127.0.0.1:9080/apisix/admin/routes/11 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -i -d '
{
"methods": ["POST"],
"uri": "/graphql",
"vars": [
["graphql_operation", "==", "query"],
["graphql_name", "==", "getRepo222"],
["graphql_root_fields", "has", "owner"]
],
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1981": 1
}
}
}'
然后我们可以根据不同的 graphql query 来进行不同的匹配,即泽轩大佬说的
泽轩:Apache APISIX 还可以针对不同的 graphql_operation 进行不同的权限校验、针对不同的 graphql_name 转发到不同的 upstream。
开始 query
curl -H 'content-type: application/graphql' -i -X POST http://127.0.0.1:9080/graphql -d '
query getRepo111 {
owner {
name
}
repo {
created
}
}'
上面的query 转发到了1980 端口的 graphql server上
curl -H 'content-type: application/graphql' -i -X POST http://127.0.0.1:9080/graphql -d '
query getRepo222 {
owner {
name
}
repo {
created
}
}'
上面的 query 转发到了 1981 端口的 graphql server 上
就是这样,先简单做一下,明天再写详细一点。
这边可能对APISIX的 upstream 配置有点问题,所以暂停一下。
如果你这样设置,会遇到一个很明显的问题,后边的配置会覆盖掉前面的配置。
主要原因是 upstream 应该分组!接下来开始正式的工作
成功示范
对第一个 upstream 服务器的配置
首先创建一个上游 upstream 对象:
curl http://127.0.0.1:9080/apisix/admin/upstreams/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
"type": "chash",
"key": "remote_addr",
"nodes": {
"127.0.0.1:1980": 1
}
}'
上游 upstream 对象创建后,均可以被具体 Route
或者 Service
引用,例如:
curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -i -d '
{
"methods": ["POST"],
"uri": "/graphql",
"vars": [
["graphql_operation", "==", "query"],
["graphql_name", "==", "getRepo111"],
["graphql_root_fields", "has", "owner"]
],
"upstream_id": "1"
}'
这里边我稍微解释一下,其中 curl http://127.0.0.1:9080/apisix/admin/routes/1
之后最后的 1
,我认为就是 "upstream_id": "1"
。因为从源码中解析 curl 请求的那个函数来看,就应该是这样的,如果有错误,可以来找我哈。
然后进行最后的正式请求:
curl -H 'content-type: application/graphql' -i -X POST http://127.0.0.1:9080/graphql -d '
query getRepo111 {
owner {
name
}
repo {
created
}
}'
得到正确的响应:
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Date: Mon, 07 Feb 2022 22:57:24 GMT
Server: APISIX/2.10.3
---Headers
x-forwarded-port:9080
content-length:85
user-agent:curl/7.29.0
accept:*/*
content-type:application/x-www-form-urlencoded
host:127.0.0.1:9080
x-real-ip:127.0.0.1
x-forwarded-for:127.0.0.1
x-forwarded-proto:http
x-forwarded-host:127.0.0.1
---Args
---URI
/graphql111
---Service Node
Centos-port: 1980
John Chever's 1980 port is working......
完成第一个 upstream 上游服务器的配置了。
对第二个 upstream 服务器的配置
首先创建一个上游 upstream 对象:
curl http://127.0.0.1:9080/apisix/admin/upstreams/2 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
"type": "chash",
"key": "remote_addr",
"nodes": {
"127.0.0.1:1981": 1
}
}'
上游 upstream 对象创建后,均可以被具体 Route
或者 Service
引用,例如:
curl http://127.0.0.1:9080/apisix/admin/routes/2 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -i -d '
{
"methods": ["POST"],
"uri": "/graphql",
"vars": [
["graphql_operation", "==", "query"],
["graphql_name", "==", "getRepo222"],
["graphql_root_fields", "has", "owner"]
],
"upstream_id": 2
}'
然后进行最后的正式请求:
curl -H 'content-type: application/graphql' -i -X POST http://127.0.0.1:9080/graphql -d '
query getRepo222 {
owner {
name
}
repo {
created
}
}'
得到正确的响应:
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Date: Mon, 07 Feb 2022 23:04:44 GMT
Server: APISIX/2.10.3
---Headers
x-forwarded-port:9080
content-length:85
user-agent:curl/7.29.0
accept:*/*
content-type:application/x-www-form-urlencoded
host:127.0.0.1:9080
x-real-ip:127.0.0.1
x-forwarded-for:127.0.0.1
x-forwarded-proto:http
x-forwarded-host:127.0.0.1
---Args
---URI
/graphql222
---Service Node
Centos-port: 1981
John Chever's 1981 port is working......
小结
这样配置好,就可以根据不同的 graphql_name
来匹配不同的上游 upstream 啦。
根据 graphql_operation 进行不同的权限校验
首先配置好上游对象实例
curl http://192.168.1.200:9080/apisix/admin/routes/11 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
"methods": ["POST"],
"uri": "/hello",
"vars": [
["graphql_operation", "==", "mutation"],
["graphql_name", "==", "repo"]
],
"upstream": {
"nodes": {
"192.168.1.200:1982": 1
},
"type": "roundrobin"
}
}'
然后发送请求以验证配置:
curl -i -X POST http://127.0.0.1:9080/hello -d '
mutation repo($ep: Episode!, $review: ReviewInput!) {
createReview(episode: $ep, review: $review) {
stars
commentary
}
}'
返回响应:
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Date: Tue, 08 Feb 2022 22:05:51 GMT
Server: APISIX/2.10.3
---Headers
content-type:application/x-www-form-urlencoded
host:127.0.0.1:9080
x-real-ip:127.0.0.1
x-forwarded-for:127.0.0.1
x-forwarded-proto:http
x-forwarded-host:127.0.0.1
x-forwarded-port:9080
content-length:133
user-agent:curl/7.29.0
accept:*/*
---Args
---URI
/hello
---Service Node
Centos-port: 1982
John Chever's 1982 port is working......
自此实现了 Apache APISIX 针对不同的 graphql_operation 进行不同的权限校验、针对不同的 graphql_name 转发到不同的 upstream。