- 后端
【免费下载链接】zoraxy
A general purpose HTTP reverse proxy and forwarding tool. Now written in Go!
本文是 Zoraxy 插件开发系列的开篇实战指南,完整讲解如何从源码构建并首次运行 Zoraxy、在其工作目录中生成plugins插件目录,以及如何搭建一个名为 "Lapwing" 的最小插件 Go 工程骨架。读完本文,你将掌握插件开发所需的全部环境准备步骤、目录结构与命名约定,并理解插件库zoraxy_plugin在开发链路中的角色,可以直接动手写出第一个可被 Zoraxy 识别与加载的插件。
开发前的三项准备
在开始编写插件之前,你的电脑上需要安装以下内容:
- Zoraxy 的源码:插件需要从 Zoraxy 源码目录中复制插件库
zoraxy_plugin,后续章节会具体说明位置与复制方式; - Go 编译器:插件以 Go 语言编写并以二进制形式分发,需要本机可用的
go工具链(当前示例工程的go.mod声明版本为go 1.23.6,参见 example/plugins/helloworld/go.mod,建议使用与之相当或更新的 Go 版本); - VSCode 或其他你熟悉的编辑器:插件开发需要一个独立的 IDE 工程窗口,推荐将插件文件夹直接作为项目根目录打开。
第一步:先运行一次 Zoraxy,生成插件目录
如果你刚刚从仓库克隆了 Zoraxy,请先进入源码目录完成构建并运行一次:
cd src/ go mod tidy go build sudo ./zoraxygo mod tidy会拉取并整理 src/go.mod 声明的全部依赖,go build在当前目录产出zoraxy可执行文件,随后以管理员权限启动。
为什么必须先运行一次?因为插件目录并不是预先存在于仓库中的,而是在 Zoraxy 启动时自动创建的。从源码看,插件管理器初始化函数会做这件事:当options.PluginDir为空时默认取"./plugins",若该目录不存在则调用os.MkdirAll创建(见 src/mod/plugins/plugins.go#L29-L36)。同时它还会创建插件分组配置文件(默认内容为空的 JSON 映射{})以及名为plugins的数据库表(见 src/mod/plugins/plugins.go#L38-L48)。
启动流程完成后,你会在 Zoraxy 的工作目录下看到一个名为plugins的文件夹,这就是所有插件(每个插件一个子目录)的存放位置。
第二步:搭建插件工程骨架
接下来为你的插件起一个名字。本教程以 "Lapwing" 为例。
命名注意事项:插件在 Introspect(自省协议)中声明的名称可以包含空格,但插件文件夹名与编译产物的二进制文件名必须不含空格和特殊字符,以保证跨平台兼容。这一约束在 Zoraxy 源码中是硬性规则:插件管理器在扫描目录时,会优先查找「与父目录同名的文件」(Windows 下为同名
.exe),其次才接受start.sh/start.bat作为入口(见 src/mod/plugins/utils.go#L27-L53)。因此文件夹名直接决定了二进制文件名,二者必须完全一致。
2.1 创建插件文件夹
在plugins文件夹下创建一个以插件名命名的目录:
plugins/Lapwing/2.2 定位并复制 Zoraxy 插件库
插件开发需要依赖 Zoraxy 提供的插件库,它在 Zoraxy 源码中的位置是:
src/mod/plugins/zoraxy_plugin将该文件夹整体复制到你自己插件的mod目录下。以与 Zoraxy 相同的命名习惯mod为例,复制完成后你的库路径应为:
plugins/Lapwing/mod/zoraxy_plugin这个库以 LGPL 许可开源,是整个插件协议的"共同语言"——Zoraxy 与插件两端共用它定义的数据结构。它至少包含以下关键内容(见 src/mod/plugins/zoraxy_plugin/zoraxy_plugin.go):
IntroSpect:插件自省结构体,声明插件的 ID、名称、作者、类型、版本、捕获路径、UI 路径、事件订阅等全部元信息;ConfigureSpec:Zoraxy 启动插件时下发的配置结构,包含监听端口、运行时常量、可选的 API Key 与 Zoraxy 端口;PluginType_Router/PluginType_Utilities两种插件类型常量(Router 型参与 HTTP 代理规则的流量处理,Utilities 型提供独立于核心的网络功能界面);ServeIntroSpect、RecvConfigureSpec、ServeAndRecvSpec等协议辅助函数,帮助插件快速完成-introspect/-configure两阶段握手。
该库是向后兼容的,从 Zoraxy 源码复制即可获得最新版本;仓库自带的批量构建脚本也是先统一把库复制到各示例插件的mod目录再执行编译(见 example/plugins/build_all.sh#L7-L17),这与你手工复制的流程完全一致。
2.3 创建 main.go 并初始化 Go 模块
在插件根目录创建入口文件,以上面的示例即:
plugins/Lapwing/main.go然后使用go mod init初始化你的插件模块:
go mod init yourdomain.com/foo/plugin_namego.mod会由 Go 编译器自动生成。例如,假设你在 GitHub 上维护 Lapwing 的源码,命令就是:
go mod init github.com/your_user_name/Lapwing仓库中的 Hello World 示例工程就是该结构的完整样板(见 example/plugins/helloworld):其go.mod只声明了模块路径example.com/zoraxy/helloworld与 Go 版本,main.go以plugin "example.com/zoraxy/helloworld/mod/zoraxy_plugin"的方式引用复制到mod目录下的插件库。一个最小化的main.go骨架如下(参考 example/plugins/helloworld/main.go 提炼):
package main import ( "fmt" "net/http" "strconv" plugin "yourdomain.com/foo/Lapwing/mod/zoraxy_plugin" ) func main() { // 处理 -introspect / -configure 两阶段协议握手 runtimeCfg, err := plugin.ServeAndRecvSpec(&plugin.IntroSpect{ ID: "com.yourdomain.Lapwing", Name: "Lapwing Plugin", Author: "your_name", AuthorContact: "you@example.com", Description: "A short description of your plugin", URL: "https://example.com", Type: plugin.PluginType_Utilities, VersionMajor: 1, VersionMinor: 0, VersionPatch: 0, UIPath: "/", }) if err != nil { panic(err) } // 在这里注册你的业务处理器,最后在 Zoraxy 分配的端口上监听 fmt.Println("Lapwing started at http://127.0.0.1:" + strconv.Itoa(runtimeCfg.Port)) err = http.ListenAndServe("127.0.0.1:"+strconv.Itoa(runtimeCfg.Port), nil) if err != nil { panic(err) } }注意ServeAndRecvSpec(对应 src/mod/plugins/zoraxy_plugin/zoraxy_plugin.go#L184-L187)先调用ServeIntroSpect:如果插件以-introspect参数启动,就打印 IntroSpect JSON 并立即退出;否则继续解析-configure=参数获取运行配置。这就是插件与 Zoraxy 之间第一个握手回合,必须放在main()的最前面。
同时请留意,IntroSpect 中的部分字段是必填的:Zoraxy 在加载插件时会对自省结果做校验,Name、Description、Author、UIPath、ID任一为空都会导致插件加载失败(见 src/mod/plugins/utils.go#L70-L86)。因此即便是最简单的骨架,也不要省略这些元信息。
第三步:在 IDE 中打开插件工程
现在打开你偏好的 IDE 或文本编辑器,将插件文件夹本身作为项目根目录打开(例如打开plugins/Lapwing/),而不是打开整个 Zoraxy 仓库。
到这里,你的插件开发环境就已完全就绪,可以开始编写真正的插件逻辑了。后续可以继续学习仓库中的 Hello World 示例、RESTful 示例 等工程,参考它们的 UI 托管、API 调用与捕获模式实现。
从工程骨架到被 Zoraxy 识别:理解背后的运行机制
为了让工程骨架真正跑起来,你需要了解 Zoraxy 如何发现并启动一个插件,这能帮你提前规避最常见的踩坑点。
三步握手协议:Introspect → Configure → Forwarding
Zoraxy 插件沿用了 dbus 设计思路,采用三步式交互协议(详见 Plugin Architecture 文档):
- Introspect(自省):Zoraxy 扫描插件目录后,以
-introspect参数执行插件入口,读取其输出的 JSON 元信息。源码中该调用带有 10 秒超时,超时或输出无法解析为 JSON 都会报错(见 src/mod/plugins/introspect.go#L52-L72)。你可以手动验证这一步:
./Lapwing -introspect正常会输出一段包含id、name、type、version_*、static_capture_paths、dynamic_capture_sniff、ui_path等字段的 JSON(完整的输出示例可参考 Introspect 文档)。
Configure(配置):Zoraxy 以
-configure=<json>参数启动插件进程,下发一个ConfigureSpecJSON,其中最重要的字段是port——一个由 Zoraxy 在 5800~6000 范围内随机挑选的空闲端口(见 src/mod/plugins/utils.go#L14-L17 与 src/mod/plugins/lifecycle.go#L42-L62)。插件必须监听127.0.0.1:<port>等待后续流量转发;若插件声明了PermittedAPIEndpoints,Zoraxy 还会同时下发 API Key 与自身端口。Forwarding(转发):插件启动后,Zoraxy 依据其 IntroSpect 中声明的捕获路径(静态捕获
static_capture_paths/ 动态捕获dynamic_capture_sniff、dynamic_capture_ingress)与 UI 路径建立反向代理,把匹配的 HTTP 流量与/plugin.ui/{plugin_id}/下的界面请求转发到插件端口。
产物命名与放置规则(最常见的坑)
编译插件时直接使用go build,默认产物名就是模块所在的目录名,例如在plugins/Lapwing/下构建会得到Lapwing。构建完成后,请把产物放回:
plugins/Lapwing/Lapwing二进制文件名必须与插件文件夹名完全一致(Windows 下为Lapwing.exe)。Zoraxy 的入口点查找逻辑明确规定了这一点:它会先查找「与父目录同名」的可执行文件,找不到才退而求其次接受start.sh/start.bat(见 src/mod/plugins/utils.go#L35-L52)。所以像Lapwing_plugin、Lapwing_plugin.exe这类命名都不会被识别。
如果你有多个插件需要批量构建,仓库提供了现成脚本 example/plugins/build_all.sh:它会自动把最新的zoraxy_plugin库复制进每个插件的mod目录,再逐个执行go mod tidy && go build,并汇总构建失败情况。
验证加载:重启 Zoraxy
新插件放好后重启 Zoraxy 即可被扫描加载;插件的启用状态会持久化到数据库中(启用调用见 src/mod/plugins/plugins.go#L191-L213)。更详细的安装步骤(包括 Linux 下需要用chmod +x为插件二进制添加执行权限、systemd 服务下用sudo systemctl restart zoraxy重启等)参见 Installing Plugin 文档。
小结与自查清单
至此,你已经完成了 Zoraxy 插件开发的完整环境搭建:构建并运行过一次 Zoraxy 生成了plugins目录、创建了plugins/Lapwing/工程、复制了zoraxy_plugin插件库、用go mod init初始化了模块,并在 IDE 中打开了工程。动手编写第一个插件前,建议按以下清单核对:
plugins目录已存在(由 Zoraxy 首次启动自动生成);- 插件库已复制到
plugins/<插件名>/mod/zoraxy_plugin; main.go中ServeAndRecvSpec位于入口最前,且ID、Name、Author、Description、UIPath均已填写;- 编译产物(
go build)与插件文件夹同名,且位于plugins/<插件名>/下; ./<插件名> -introspect能正常输出合法 JSON;- 重启 Zoraxy 后插件出现在插件列表中。
完成骨架搭建后,下一步建议阅读仓库中的 What is Zoraxy Plugin 了解插件与核心 PR 的取舍、插件类型与分发方式,再通过 Hello World 示例 与 Basic Examples 章节 学习第一个可运行的完整插件实现。
- 后端
【免费下载链接】zoraxy
A general purpose HTTP reverse proxy and forwarding tool. Now written in Go!
相关推荐
电视盒子装 TVBoxOS 不用自己编译:TVBoxOSC 自动打包 APK 上手指南
电视盒子装 TVBoxOS 不用自己编译:TVBoxOSC 自动打包 APK 上手指南 TVBoxOSC 是一个面向电视盒子的开源项目,它自动拉取并编译两个上游
Jasminum插件开发环境搭建:从零开始构建你的第一个Zotero插件
想要为Zotero开发中文元数据抓取插件?Jasminum插件为你提供了完美的起点!这个终极指南将带你从零开始,快速搭建专业的Zotero插件开发环境,让你轻松
科研TinyConsole扩展机制详解:如何为控制台添加自定义按钮和功能
TinyConsole扩展机制详解:如何为控制台添加自定义按钮和功能 TinyConsole是一款专为iOS应用设计的轻量级调试控制台工具,能够在没有开发电脑连
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考