本文基于 APISIX 3.2 版本进行插件开发并运行通过。

APISIX 目前开发插件比较简单,只需要编写 Lua 源代码并放到默认的插件目录下,然后通过配置文件开启插件即可,我们如果使用 Docker 运行 APISIX 那么默认的安装目录是:/usr/local/apisix,插件目录是:/usr/local/apisix/apisix/plugins ,我们只需要修改这个目录已有的插件源码或者自己编写新的插件放到这个目录,编写完成并启用后,重启 APISIX 将会自动加载。因为使用 Docker 启动,我们可以直接在外部编写插件并且映射到容器内部指定的位置即可。

如果是在第三方的目录编写插件,那么 APISIX 要求插件父目录必须包含:apisix/plugins 子目录,也就是和默认的层级结构一致,比如插件的目录为:/opt/apisix-plugins ,那么实际编写插件位置应该是在:/opt/apisix-plugins/apisix/plugins 。同样是对于容器来说外面并不需要建这么多的层级,映射进去的时候指定就可以,然后需要修改配置文件,添加外部路径:

apisix:
# ...
extra_lua_path: "/opt/apisix-plugins/?.lua"

外部路径中相同名称的插件会覆盖现有的插件。

如果选择在默认目录下开发,那么不需要进行上面的配置,开发可以参考内部的 example-plugin.lua 这个插件,这是一个示例代码,默认也启用了,直接复制这个改即可,比如我们创建一个 example-plugin2.lua,代码如下:

--
-- Licensed to the Apache Software Foundation (ASF) under one or more
-- contributor license agreements. See the NOTICE file distributed with
-- this work for additional information regarding copyright ownership.
-- The ASF licenses this file to You under the Apache License, Version 2.0
-- (the "License"); you may not use this file except in compliance with
-- the License. You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
local ngx = ngx
local core = require("apisix.core")
local plugin = require("apisix.plugin") local schema = {
type = "object",
properties = {
name = {type = "string"},
version = {type = "integer"},
},
required = {"name"},
} local plugin_name = "example-plugin2" local _M = {
version = 0.1,
priority = 99,
name = plugin_name,
schema = schema,
} function get_username()
local req_headers = ngx.req.get_headers()
local username = req_headers.user
if username ~= "" then
return username
end
return nil
end function _M.check_schema(conf, schema_type)
if schema_type == core.schema.TYPE_METADATA then
return core.schema.check(metadata_schema, conf)
end
return core.schema.check(schema, conf)
end function _M.init()
-- call this function when plugin is loaded
local attr = plugin.plugin_attr(plugin_name)
if attr then
core.log.info(plugin_name, " get plugin attr val: ", attr.val)
end
end function _M.destroy()
-- call this function when plugin is unloaded
end function _M.rewrite(conf, ctx)
core.log.warn("plugin rewrite phase, conf: ", core.json.encode(conf))
core.log.warn("plugin rewrite phase, ctx: ", core.json.encode(ctx, true))
core.log.warn("plugin rewrite phase, username: ", get_username())
end function _M.access(conf, ctx)
core.log.warn("plugin access phase, conf: ", core.json.encode(conf))
core.log.warn("plugin access phase, ctx: ", core.json.encode(ctx, true))
core.log.warn("plugin access phase, ngx headers: ", core.json.encode(ngx.req.get_headers()))
end local function hello()
local args = ngx.req.get_uri_args()
if args["json"] then
return 200, {msg = "world"}
else
return 200, "world\n"
end
end function _M.control_api()
return {
{
methods = {"GET"},
uris = {"/v1/plugin/example-plugin2/hello"},
handler = hello,
}
}
end return _M

这就是一个比较简单的插件,其中没设置元数据,其余的部分简单说下:

  1. schema 表示插件的配置需要在启用时指定
  2. _M 表示一个插件实例,可以指定名称、版本、优先级、schema 等,优先级建议设置 0~ 100 之间的值。
  3. 然后我们就可以给 _M 绑定不同的方法,按照请求阶段分别为:init、check_schema、rewrite、access、before_proxy、header_filter、body_filter、log 等阶段,我们需要选择适合的阶段进行处理。另外还有 control_api 方法,由插件提供并定义响应结果,可以监控插件的一些信息等。

我们上面这个插件就是简单打印了一些信息,编写了一个函数获取 Header 里面的用户,然后我们需要复制 config-default.yaml 配置文件中的 plugins 配置项并填写到 config.yaml 中,因为之前的插件都要保留着不要给覆盖掉了,具体 config.yaml 中的内容如下:

plugins:                           # plugin list (sorted by priority)
- real-ip # priority: 23000
- ai # priority: 22900
- client-control # priority: 22000
- proxy-control # priority: 21990
- request-id # priority: 12015
- zipkin # priority: 12011
#- skywalking # priority: 12010
#- opentelemetry # priority: 12009
- ext-plugin-pre-req # priority: 12000
- fault-injection # priority: 11000
- mocking # priority: 10900
- serverless-pre-function # priority: 10000
#- batch-requests # priority: 4010
- cors # priority: 4000
- ip-restriction # priority: 3000
- ua-restriction # priority: 2999
- referer-restriction # priority: 2990
- csrf # priority: 2980
- uri-blocker # priority: 2900
- request-validation # priority: 2800
- chaitin-waf # priority: 2700
- openid-connect # priority: 2599
- cas-auth # priority: 2597
- authz-casbin # priority: 2560
- authz-casdoor # priority: 2559
- wolf-rbac # priority: 2555
- ldap-auth # priority: 2540
- hmac-auth # priority: 2530
- basic-auth # priority: 2520
- jwt-auth # priority: 2510
- key-auth # priority: 2500
- consumer-restriction # priority: 2400
- forward-auth # priority: 2002
- opa # priority: 2001
- authz-keycloak # priority: 2000
#- error-log-logger # priority: 1091
- proxy-cache # priority: 1085
- body-transformer # priority: 1080
- proxy-mirror # priority: 1010
- proxy-rewrite # priority: 1008
- workflow # priority: 1006
- api-breaker # priority: 1005
- limit-conn # priority: 1003
- limit-count # priority: 1002
- limit-req # priority: 1001
#- node-status # priority: 1000
- gzip # priority: 995
- server-info # priority: 990
- traffic-split # priority: 966
- redirect # priority: 900
- response-rewrite # priority: 899
- degraphql # priority: 509
- kafka-proxy # priority: 508
#- dubbo-proxy # priority: 507
- grpc-transcode # priority: 506
- grpc-web # priority: 505
- public-api # priority: 501
- prometheus # priority: 500
- datadog # priority: 495
- loki-logger # priority: 414
- elasticsearch-logger # priority: 413
- echo # priority: 412
- loggly # priority: 411
- http-logger # priority: 410
- splunk-hec-logging # priority: 409
- skywalking-logger # priority: 408
- google-cloud-logging # priority: 407
- sls-logger # priority: 406
- tcp-logger # priority: 405
- kafka-logger # priority: 403
- rocketmq-logger # priority: 402
- syslog # priority: 401
- udp-logger # priority: 400
- file-logger # priority: 399
- clickhouse-logger # priority: 398
- tencent-cloud-cls # priority: 397
- inspect # priority: 200
#- log-rotate # priority: 100
# <- recommend to use priority (0, 100) for your custom plugins
- example-plugin # priority: 0
#- gm # priority: -43
- aws-lambda # priority: -1899
- azure-functions # priority: -1900
- openwhisk # priority: -1901
- openfunction # priority: -1902
- serverless-post-function # priority: -2000
- ext-plugin-post-req # priority: -3000
- ext-plugin-post-resp # priority: -4000
- example-plugin2 # priority: 99

上面最后一项就是我们自定义的插件,然后如果是使用 Docker Compose 启动,插件可以映射如下:

version: "3"

services:
apisix:
# ...
volumes:
- ./conf/config.yaml:/usr/local/apisix/conf/config.yaml:ro
# 自定义插件映射
- ./plugins/example-plugin2.lua:/usr/local/apisix/apisix/plugins/example-plugin2.lua

然后我们重启启动 APISIX,启动没有报错可以尝试添加路由:

curl -XPUT 127.0.0.1:9180/apisix/admin/routes/example2 -H 'X-API-KEY: <admin-key>' -d '
{
"plugins": {
"example-plugin2": {
"name": "example2"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
},
"uri": "/hello"
}'

然后我们访问数据平面服务即可:

curl -XGET 127.0.0.1:9080/hello

这时候我们看 APISIX 的日志就可以看到我们插件打印出的详细信息了,基于上面的插件开发运行的原理可以根据需要编写更多的代码来扩展功能。

Reference:

  1. https://apisix.apache.org/docs/apisix/3.2/plugin-develop/
  2. https://www.cnblogs.com/loseself/p/16151876.html

APISIX 简单的自定义插件开发步骤的更多相关文章

  1. discuz特殊主题插件开发步骤和犯的愚蠢错误

    discuz作为国内流行的论坛系统,可谓造福了不少趣味相投的网友们.它让天南地北.国内外有着共同兴趣爱好的人们聚集在一起,分享彼此的喜怒哀乐.心得体会.然而作为discuz的使用者之一,还是个码农,然 ...

  2. Android自定义view(一):制作一个最最最简单的自定义view

    转载:https://blog.csdn.net/wsyizmao/article/details/78491422 浅谈安卓自定义view(一):制作一个最最最简单的自定义view 对于安卓程序员来 ...

  3. Cordova自定义插件开发

    Cordova自定义插件开发 一.创建Cordova项目 在创建项目前请确保安装Cordova Cordova环境配置:https://www.w3cschool.cn/cordova/cordova ...

  4. [原] Android 自定义View步骤

    例子如下:Android 自定义View 密码框 例子 1 良好的自定义View 易用,标准,开放. 一个设计良好的自定义view和其他设计良好的类很像.封装了某个具有易用性接口的功能组合,这些功能能 ...

  5. 最简单的自定义适配器adapter

    下面是一个非常简单的自定义适配器的总体源码,从这个源码入门,就可以慢慢学会适配器了 适配器的作用: 完成数据和界面控件的绑定,把数据绑定到界面的现实控件条目上(对于listView,应该是listVi ...

  6. 一个简单的jQuery插件开发实例

    两年前写的一个简单的jQuery插件开发实例,还是可以看看的: <script type="text/javascript" src="jquery-1.7.2.m ...

  7. java:jsp: 一个简单的自定义标签 tld

    java:jsp: 一个简单的自定义标签 tld 请注意,uri都是:http://www.tag.com/mytag,保持统一,要不然报错,不能访问 tld文件 <?xml version=& ...

  8. js/jq基础(日常整理记录)-4-一个简单的自定义tree插件

    一.一个简单的自定义tree插件 上一篇是之前自定义的table插件,这一篇也是之前同期尝试做的一个tree插件. 话不多说,先看看长什么样子哈! 现在来看确实不好看,以后在优化吧! 数据源:ajax ...

  9. wxwidget自定义消息处理步骤

    from http://www.cppblog.com/kenlistian/archive/2009/02/06/73096.html 略有修改 wxwidget自定义消息处理步骤 自定义消息处理( ...

  10. 简单的JDBC编程步骤

    1.加载数据库驱动(com.mysql.jdbc.Driver) 2.创建并获取数据库链接(Connection) 3.创建jdbc statement对象(PreparedStatement) 4. ...

随机推荐

  1. Linux IPC(进程间通信)摘要(信号灯,共享内存,消息队列,管道)(一)

    PS:要转载请注明出处,本人版权所有. PS: 这个只是基于<我自己>的理解, 如果和你的原则及想法相冲突,请谅解,勿喷. 前置说明   本文作为本人csdn blog的主站的备份.(Bl ...

  2. Android 开发Day2

    我的是小刺猬版本,算是比较新的版本了,还有火烈鸟和蜻蜓版啥的 新建项目(project)点击加号新建就行了.这时我们会选择一个模板作为开发的辅助起点,看上哪个就选哪个就行了.推荐新手选空项目(Empt ...

  3. 建民的Java小课堂

    Java Java快问快答: 1.JAVA的基本运行单位是类还是方法? 很明显是类 2.类由什么组成? 由特性和行为的对象组成 3.变量的类型,相互之间可以转换吗,浮点数? 答案是可以 int i=9 ...

  4. Button按钮Effect的用法

    教大家写一个好看的Button按钮 代码简单粗暴 <Grid > <Border Width="200" Height="30" Margin ...

  5. [前端原生技术]jsonp

    [版权声明]未经博主同意,谢绝转载!(请尊重原创,博主保留追究权)https://www.cnblogs.com/cnb-yuchen/p/18031965出自[进步*于辰的博客] 在学习了Jsoup ...

  6. Elasticsearch索引不存在时,查询接口报错怎么办?

    1.索引不存在,报错:type=index_not_found_exception, reason=no such index解决办法: DSL: GET /text_index_003/_searc ...

  7. veriog之四位全加器

    verilog之四位全加器 1.简易代码 module adder_4bit ( cout,sum,ina,inb,cin ); output[3:0] sum; output cout; input ...

  8. KingbaseES 数据库使用Limit子句查询结果返回顺序不一致

    一.KingbaseES数据库limit查询子句: 在KingbaseES数据库使用LIMIT子句限制查询结果的行数,从而实现分段显示数据的功能. 使用LIMIT子句在KingbaseES数据库中进行 ...

  9. (1,3,4,2,5)小和问题【Java】

    01[1,3,4,2,5]求小和 从右往左看:左边比右边小的加和到一起! 1 左边没有数 0 3 1 4 1+3 2 1 5 1+3+4+2 从左往右看:有几个数右边比左边大 1 4个数: 3 4 2 ...

  10. CSS样式中的各种居中方式

    1.水平居中 将margin-left和margin-right属性设置为auto,从而达到水平居中的效果. 代码: margin:0 auto; 2.文字水平垂直居中 利用line-height设为 ...