乐趣区

关于后端:使用-Java-编写-Apache-APISIX-插件

Apache APISIX 反对多语言编写插件了!不会 Lua 也没关系,当初能够用你相熟的语言编写插件,在官网查看还有视频教程。

1. 简介

1.1 为什么 Apache APISIX 要反对多语言编写插件

在反对多语言编程插件前,Apache APISIX 只反对应用 Lua 语言编写插件,须要开发者把握 Lua 和 OpenResty 相干的开发能力。然而绝对于支流开发语言 Java、Go 来说,Lua 和 OpenResty 属于绝对小众的技术,开发者很少。如果从头开始学习 Lua 和 OpenResty,须要付出相当多的工夫和精力。

开发团队在进行技术选型的时候,最重要的考量就是所选技术是否与本团队技术栈相匹配,然而小众的技术栈就限度了 Apache APISIX 在更广大的场景下进行技术落地。

当初 Apache APISIX 反对多语言开发插件,更重要的是反对语言所在的开发生态圈,使用者能够应用本人相熟的技术栈来开发 Apache APISIX。以反对 Java 为例,使用者不仅能够应用 Java 语言编写插件,还能够融入 Spring Cloud 生态圈,宽泛应用生态圈内的各种技术组件。

1.2 Apache APISIX 多语言反对架构图

上图右边是 Apache APISIX 的工作流程,左边的 plugin runner 是指插件运行器,泛指多语言反对的我的项目。本文档上面提到的 apisix-java-plugin-runner 我的项目就是反对 Java 语言的 plugin runner。

当你在 Apache APISIX 中配置一个 plugin runner 时,Apache APISIX 会启动一个子过程运行 plugin runner,该子过程与 Apache APISIX 过程属于同一个用户。当咱们重启或从新加载 Apache APISIX 时,plugin runner 也将被重启。

如果你为一个给定的路由配置了 ext-plugin-* 插件,击中该路由的申请将触发 Apache APISIX,通过 unix socket 向 plugin runner 执行 RPC 调用。调用细分为两个阶段:

  • ext-plugin-pre-req: 在执行 Apache APISIX 内置插件 (Lua 语言插件) 之前
  • ext-plugin-post-req: 在执行 Apache APISIX 内置插件 (Lua 语言插件) 之后

依据须要配置 plugin runner 的执行机会。

plugin runner 会解决 RPC 调用,在其外部创立一个模仿申请,而后运行多语言编写的插件,并将后果返回给 Apache APISIX。

多语言插件的执行程序是在 ext-plugin-* 插件配置项中定义的。像其余插件一样,它们能够被启用并在运行中从新定义。

2. 搭建开发环境

首先须要搭建 Apache APISIX 的运行环境或者开发环境,参考 构建 Apache APISIX,以及 Java 我的项目的开发环境,参考 构建 apisix-java-plugin-runner。
留神:Apache APISIX 和 apisix-java-plugin-runner 须要位于同一实例上。

3. 进入调试模式

3.1 设置 Apache APISIX 进入调试模式

这里是指让 Apache APISIX 以调试的形式运行内部插件,在 config.yaml 中减少以下配置

ext-plugin:
  path_for_test: /tmp/runner.sock

这个配置的意思是,Apache APISIX 相当于 client 端,会监听位于 /tmp/runner.sock 地位上的 Unxi Domain Socket 链接。

3.2 设置 apisix-java-plugin-runner 进入调试模式

在启动 Main class(org.apache.apisix.plugin.runner.PluginRunnerApplication)之前,须要配置用户级的环境变量 APISIX_LISTEN_ADDRESS=unix:/tmp/runner.sockAPISIX_CONF_EXPIRE_TIME=3600

如果你是应用 IDEA 进行开发,那么配置好的环境变量示意如下:

apisix-java-plugin-runner 相当于 server 端,在启动时会被动创立 /tmp/runner.sock 文件,并在这个文件上与 Apache APISIX 进行 Unix Domain Socket 通信。

4. 开发

4.1 场景

咱们以一个场景来代入开发过程:须要验证申请 header 中 token 的有效性,验证 token 的形式是用申请中携带 token 作为参数,拜访 SSO 固定的接口,如果 token 验证通过则放行申请,验证失败则阻止申请。

4.2 配置 Apache APISIX

先给插件命名为 TokenValidator,而后设计属性,为了尽可能做到动静配置,属性设计如下

{
  "validate_header": "token",
  "validate_url": "https://www.sso.foo.com/token/validate",
  "rejected_code": "403"
}

启动 Apache APISIX,而后新增一条路由配置,指定该路由须要调用 apisix-java-plugin-runner 的 TokenValidator 插件,示例如下

curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '{"uri":"/get","plugins":{"ext-plugin-pre-req":{"conf":[
                {
                    "name":"TokenValidator",
                    "value":"{\"validate_header\":\"token\",\"validate_url\":\"https://www.sso.foo.com/token/validate\",\"rejected_code\":\"403\"}"
                }
            ]
        }
    },
    "upstream":{
        "nodes":{"httpbin.org:80":1},
        "type":"roundrobin"
    }
}

须要留神的是,TokenValidator 的属性须要通过 json 本义,作为 string 类型进行配置。

(这里上游地址配置为 httpbin.org,不便调试)

4.3 开发 Java 插件

在 runner-plugin/src/main/java/org/apache/apisix/plugin/runner/filter 目录下,新增 TokenValidatr.java,代码初始骨架如下

package org.apache.apisix.plugin.runner.filter;

import org.apache.apisix.plugin.runner.HttpRequest;
import org.apache.apisix.plugin.runner.HttpResponse;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;


@Component
public class TokenValidator implements PluginFilter {

    @Override
    public String name() {return "TokenValidator";}

    @Override
    public Mono<Void> filter(HttpRequest request, HttpResponse response, PluginFilterChain chain) {return chain.filter(request, response);
    }
}

须要继承 PluginFilter接口,重写 namefilter函数。

重写 name 的返回值,和后面配置 APISIX 的路由属性中 “name” 保持一致。

残缺代码如下:

package org.apache.apisix.plugin.runner.filter;

import com.google.gson.Gson;
import org.apache.apisix.plugin.runner.HttpRequest;
import org.apache.apisix.plugin.runner.HttpResponse;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

import java.util.HashMap;
import java.util.Map;

@Component
public class TokenValidator implements PluginFilter {

    @Override
    public String name() {return "TokenValidator";}

    @Override
    public Mono<Void> filter(HttpRequest request, HttpResponse response, PluginFilterChain chain) {
        // parse `conf` to json
        String configStr = request.getConfig(this);
        Gson gson = new Gson();
        Map<String, Object> conf = new HashMap<>();
        conf = gson.fromJson(configStr, conf.getClass());

        // get configuration parameters
        String token = request.getHeader((String) conf.get("validate_header"));
        String validate_url = (String) conf.get("validate_url");
        boolean flag = validate(token, validate_url);

        // token verification results
        if (!flag) {String rejected_code = (String) conf.get("rejected_code");
            response.setStatusCode(Integer.parseInt(rejected_code));
            return chain.filter(request, response);
        }

        return chain.filter(request, response);
    }

    private Boolean validate(String token, String validate_url) {
        //TODO: improve the validation process
        return true;
    }
}

4.4 测试

在 Apache APISIX 上配置的上游服务是 httpbin.org,能够拜访 Apache APISIX,触发路由,让 Apache APISIX 调用 apisix-java-plugin-runner 去执行 TokenValidator 插件,测试一下 Java 插件成果。

curl -H 'token: 123456' 127.0.0.1:9080/get 
{"args": {}, 
 "headers": {
 "Accept": "/", 
 "Host": "127.0.0.1", 
 "Token": "123456", 
 "User-Agent": "curl/7.71.1", 
 "X-Amzn-Trace-Id": "Root=1-60cb0424-02b5bf804cfeab5252392f96", 
 "X-Forwarded-Host": "127.0.0.1"
 }, 
 "origin": "127.0.0.1", 
 "url": "http://127.0.0.1/get"
}

5. 部署

插件开发实现后,部署操作能够参考 部署 apisix-java-plugin-runner。

6. 视频教程

在官网查看还有视频教程

关注公众号,浏览最新技术文章。

退出移动版