hz:Hertz 框架官方 IDL 代码生成器完整使用指南
2026/9/16 23:17:10 网站建设 项目流程

hz:Hertz 框架官方 IDL 代码生成器完整使用指南

【免费下载链接】hertzGo HTTP framework with high-performance and strong-extensibility for building micro-services.项目地址: https://gitcode.com/GitHub_Trending/he/hertz

hz是 Hertz 目录。它负责解析 Thrift / Protobuf 两种 IDL(Interface Definition Language)文件,并一键生成完整可运行的 Hertz 项目脚手架,包括 handler、路由、model 数据模型与 client 客户端代码。阅读本文后,你将掌握hz new / update / model / client四大命令的完整用法、全部核心参数含义、自定义模板机制,以及 CLI 与插件双模式运行的底层原理。

快速上手

在仓库的cmd/hz目录下构建二进制,然后即可基于 IDL 生成项目:

# 构建 cd cmd/hz && go build -o hz . # 从 Thrift IDL 生成新项目 hz new --idl api.thrift --module github.com/example/myservice # 从 Protobuf IDL 生成新项目 hz new --idl api.proto --module github.com/example/myservice # IDL 变更后增量更新已有项目(模块名自动从 go.mod 读取) hz update --idl api.thrift # 仅生成 model 代码(模块名自动从 go.mod 读取) hz model --idl api.thrift # 生成 client 代码(模块名自动从 go.mod 读取) hz client --idl api.thrift --base_domain localhost:8888

--module(别名--mod)用于指定 Go module 名称。若当前目录或其上层目录已存在go.mod,hz 会通过util.SearchGoMod自动探测模块名,无需再手动指定;若未指定且找不到go.mod,则会以 GOPATH 相对路径作为模块名并自动生成go.mod(对应源码逻辑见 config/argument.go 的checkPackage实现)。

四大命令

命令说明
new从 IDL 搭建全新 Hertz 项目,生成工程布局、handler、路由与 model
update为 IDL 中新增的方法增量添加 handler/路由,不覆盖已有代码
model仅根据 IDL 类型生成 Go 结构体定义(models)
client根据 IDL service 定义生成 Hertz HTTP 客户端代码

命令入口定义在 app/app.go 的Init()中,每个命令都通过urfave/cli注册并绑定各自支持的 flag 集合;main.go首先调用app.PluginMode()检查插件模式(见下文架构部分),随后进入正常 CLI 流程(main.go)。

参数(Flags)全解

全局参数

参数说明
--verbose,-vv开启 verbose(debug 级别)日志

--verbose会调用logs.SetLevel(logs.LevelDebug)输出详细调试信息;不开时默认只输出 warning 级别以上日志(app/app.go)。

项目结构相关参数

参数适用命令说明
--idl全部IDL 文件路径(.thrift.proto),可多次指定
--module,--mod全部Go module 名称(若存在go.mod则自动探测)
--servicenew服务名(默认:hertz_service
--out_dirnew,update,model项目输出目录(默认:当前目录)
--handler_dirnew,updatehandler 目录,相对out_dir(默认:biz/handler
--model_dir全部model 目录,相对out_dir(默认:biz/model
--router_dirnewrouter 目录,相对out_dir(默认:biz/router
--client_dirnew,update,clientclient 输出目录。对new/update:不指定则不生成 client 代码;对client:默认使用由 IDL 推导的路径
--force_client_dirclientclient 输出目录,不带 IDL 命名空间子目录
--usenew,update,client从外部包导入 model,而非本地生成

默认目录常量biz/modelbiz/routerbiz/handler定义于 meta/const.go。注意:handler_dirmodel_dirrouter_dir等必须为相对out_dir的相对路径,绝对路径会直接报错(config/argument.go 的checkPath)。--use的场景通常是 model 由独立的公共仓库统一维护,此时 hz 会跳过本地的 model 生成(Thrift 场景下还会输出提示信息'model code' is not generated due to the '-use' option,见 meta/const.go)。

代码生成参数

参数适用命令说明
--handler_by_methodnew,update每个方法生成独立 handler 文件(默认:每个 service 一个文件)
--sort_routernew,update对路由注册代码排序,保证输出确定性
--no_recurse全部只生成主 IDL 的 model,跳过 include/import 的依赖 IDL
--force,-fnew强制覆盖已有项目
--force_clientclient即使hertz_client.go已存在也强制重新生成
--base_domainclient生成的 client 代码中默认请求域名
--enable_extendsnew,update,client解析 Thrift IDL 中的extends关键字

--handler_by_method对应两种 handler 生成模式:默认的"按 service"模式将所有 handler 汇聚在一个文件(如user_service.go),update时通过handler_single.go模板追加新方法;"按方法"模式则为每个方法生成独立文件(如create_user.go),update时新建文件但绝不修改已有文件(详见 DESIGN.md 的 Handler Generation 小节)。

Struct Tag 参数

参数适用命令说明
--snake_tag全部formqueryjsontag 使用 snake_case 命名
--json_enumstr全部JSON 枚举字段使用字符串值而非数字(仅 Thrift)
--unset_omitempty全部移除生成结构体 tag 中的omitempty
--pb_camel_json_tag全部JSON tag 使用 camelCase(仅 Protobuf)
--rm_tag全部移除默认 tag(如--rm_tag json)。显式注解的 tag 会被保留
--query_enumintclientclient 代码中枚举 query 参数使用数值
--enable_optionalclientThrift 可选字段未设置时不放入 query 参数

这些 tag 选项最终通过GetThriftgoOptions拼接到 thriftgo 的go:生成选项字符串中——默认选项为reserve_comments,gen_json_tag=false--json_enumstr会追加json_enum_as_text,并总是追加package_prefix=以保证生成 import 路径与输出结构一致(config/cmd.go)。

IDL 编译器透传参数

参数适用命令说明
--proto_path,-I全部添加 Protobuf import 的搜索路径
--thriftgo,-t全部透传给 thriftgo 的参数(如-t naming_style=golint
--protoc,-p全部透传给 protoc 的参数
--thrift-pluginsnew,update,client额外的 thriftgo 插件({name}:{options}
--protoc-pluginsnew,update,client额外的 protoc 插件({name}:{options}:{out_dir}
--option_package,-Pnew,update将 IDL include 路径映射为 Go import 路径({include}={import}
--trim_gopackage,--trim_pkg全部裁剪 protobufgo_package前缀,避免生成过深的嵌套目录

以 Protobuf 场景为例,BuildPluginCmd会为 protoc 构造--plugin=protoc-gen-hertz=<hz二进制路径>--hertz_out=<输出目录>--hertz_opt=<序列化参数>三个关键参数(config/cmd.go);protoc 插件必须以plugin_name:options:out_dir三段式传入,否则会直接报错退出。protoc 的 well-known types 需要额外的-Iinclude 路径,这点在generate.sh中体现得很清楚(自动探测 protoc 同级 include 目录或/usr/include/usr/local/include等系统路径)。

模板定制参数

参数适用命令说明
--customize_layoutnew自定义工程布局模板 YAML 路径
--customize_layout_data_pathnew渲染布局模板用的 JSON 数据文件路径
--customize_packagenew,update,client自定义 package 模板 YAML(覆盖 handler/router/middleware 模板)
--exclude_file,-E全部排除某文件路径,不生成/不更新

--customize_layout指定布局配置后,GenerateLayout会读取该 YAML 替代默认布局(app/app.go);若同时提供了--customize_layout_data_path的 JSON 数据文件,则完全由数据文件驱动渲染(GenerateByConfig,见 generator/layout.go),否则仍然按 service 信息渲染。

自定义模板(Custom Templates)

hz 的全部生成代码都由 Go template 渲染。创建一个 YAML 配置文件,并用--customize_package传入:

layouts: - path: biz/handler/handler.go # 覆盖默认 handler 模板 delims: ["{{", "}}"] body: | package {{.PackageName}} // your custom handler template... - path: biz/custom/{{.ServiceName}}.go # 新建文件,path 支持模板变量 delims: ["{{", "}}"] loop_service: true # 每个 service 生成一个文件 update_behavior: type: append # update 时的行为:skip/cover/append append_key: method # 按 method 或 service 追加 append_content_tpl: | // new method: {{.Name}} body: | package custom // your template...

模板的 update 行为有三种:

  • skip—— 不修改已存在的文件;
  • cover—— 完全覆盖已有文件;
  • append—— 向已有文件追加新内容(例如新增的 handler 方法)。

模板系统还支持自定义定界符(当你的模板本身包含 Go template 语法、需要避开{{ }}冲突时非常有用)、按 service 循环(loop_service)或按 method 循环(loop_method)生成多份文件等能力(DESIGN.md)。

示例输出:用 generate.sh 验证生成结果

仓库提供了 generate.sh,使用cmd/hz/testdata下的测试 IDL 文件(Thrift 与 Protobuf2/3 两套 psm 用例)完整跑一遍new → update → model → client全流程:

cd cmd/hz # 为所有 IDL 类型生成示例(输出到 generate_out/) ./generate.sh # 只生成指定目标 ./generate.sh thrift proto3 # CI 模式:生成 → 校验产物可编译 → 清理 ./generate.sh --verify --clean

可选目标:thriftproto2proto3handler_by_method(不传则默认全部)。脚本细节:

  • --verify会对每个目标执行go mod tidy && go build .,确保生成的代码真实可编译;
  • --clean在验证通过后删除输出目录,适合 CI 流水线;
  • --hz PATH可指定 hz 二进制路径,默认从源码go build -o hz .构建;
  • 每个目标在子目录中依次执行hz new(带-f强制覆盖)、hz updatehz modelhz client --client_dir=hertz_client,完整覆盖四个命令的可运行性;
  • Protobuf 目标会尝试定位 protoc 的 well-known types include 目录并作为-I传入(generate.sh)。

对应的测试 IDL 文件位于 cmd/hz/testdata/thrift/psm.thrift、cmd/hz/testdata/protobuf3/psm/psm.proto 等路径,可作为编写自定义 IDL 的参考样本。

依赖的 IDL 编译器

  • thriftgo—— Thrift 编译器。若系统中不存在,hz 会自动安装最新版本;若已存在但版本低于 v0.2.0,也会自动更新到最新版(逻辑见 config/cmd.go 的lookupTool);
  • protoc—— Protobuf 编译器,必须手动安装,hz 不会自动安装(若缺失会直接提示 "please install it first")。

lookupTool的查找顺序为:PATH中的thriftgo/protoc$GOPATH/bin下的同名工具。Thrift 场景下若go.mod中缺少replace github.com/apache/thrift => github.com/apache/thrift v0.13.0,hz 还会在new结束时给出对应警告提示(meta/const.go)。

架构:CLI 与插件双模式执行

hz 内部采用"CLI 模式 + 插件模式"双模式设计,完整设计文档见 cmd/hz/DESIGN.md。

双模式执行模型

  1. CLI 模式(正常模式):解析命令行参数、生成工程布局,然后以子进程方式调用 IDL 编译器(thriftgo/protoc);
  2. 插件模式:当被 IDL 编译器以插件方式回调(thrift-gen-hertz/protoc-gen-hertz)时,从 stdin 读取解析好的 AST,生成 Hertz 专属代码。

因此一条hz new命令实际上会运行两次 hz:

User -> hz (CLI mode) -> thriftgo/protoc -> hz (Plugin mode) -> generated code

插件模式通过环境变量HERTZ_PLUGIN_MODE检测——CLI 在调用编译器前会设置该变量(config/cmd.go),main()开头的app.PluginMode()则检查该变量并决定是否以插件身份执行(app/app.go、main.go)。

代码生成流水线

  1. 布局生成(仅new命令):创建工程骨架——含 Hertz server 启动代码的main.go、含依赖声明的go.mod、路由注册入口router.go,以及biz/handler/biz/model/biz/router/目录结构。默认main.go模板内容为server.Default()+register(h)+h.Spin(),可直接在 generator/layout_tpl.go 中查看;完整默认布局(含biz/dalbiz/servicescriptconf等目录)也在该文件中定义;
  2. 插件执行:IDL 编译器解析.thrift/.proto文件后,把 AST 传给插件模式下的 hz。插件先转换AST 为内部的ServiceHttpMethod结构体,提取 HTTP 注解(路径、方法、序列化方式),再解析跨 IDL 文件的类型引用为 Go import 路径,最后通过HttpPackageGenerator生成代码;
  3. Handler 生成:见上文--handler_by_method说明;
  4. 路由生成:路由以树结构(RouterNode)组织,通过插入每个方法的 HTTP path 构建;随后遍历树为中间件分组分配唯一名称(DyeGroupName),渲染为r.Group()/r.GET()等 Go 路由注册代码,并为每个路由组生成中间件 stub;
  5. 模板系统:支持自定义定界符、三种 update 行为、按 service/method 循环生成,以及通过--customize_package覆盖任意默认模板。

.hz清单文件与参数传递

项目根目录的.hzYAML 文件(由hz new生成)记录了三类信息:

  • 生成该项目所用的 hz 版本;
  • handler、model、router 目录路径。

这使hz update无需用户重复指定全部参数即可定位已有生成代码——update命令会先通过InitAndValidate加载并校验.hz(缺失或版本非法都会报错),再用其中的目录信息补全参数(app/app.go、meta/manifest.go)。.hz文件内容大致形如:

// Code generated by hz. DO NOT EDIT. hz version: v0.9.7 handlerDir: biz/handler modelDir: biz/model routerDir: biz/router

由于插件是 IDL 编译器的子进程而非 hz 的直接子进程,CLI 与插件之间的参数传递通过反射序列化完成:util.PackArgs将参数打成逗号分隔字符串,经编译器插件选项透传,插件再用util.UnpackArgs反序列化还原(DESIGN.md)。格式形如FieldName=value,SliceField=val1;val2;val3,MapField=k1=v1;k2=v2

小结

hz 为 Hertz 项目提供了一条"IDL 即代码"的完整链路:new搭建骨架、update增量演进、model单独产出数据层、client一键生成调用方。通过丰富的 tag 风格选项、编译器参数透传、可深度定制的模板系统,以及.hz清单驱动的增量更新机制,它能够稳定适配从个人微服务到大规模团队协作的代码生成需求。若需深入源码,建议从 app/app.go(命令编排)、generator(生成引擎)、thrift 与 protobuf(两套 IDL 插件)三条主线入手阅读。

【免费下载链接】hertzGo HTTP framework with high-performance and strong-extensibility for building micro-services.项目地址: https://gitcode.com/GitHub_Trending/he/hertz

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询