前言
大项目作业我们团队打算使用Hertz + gorm的方案。然而之前并没有学习过Hertz,网上也没有什么视频资料,大多是零星的文字材料,唯一可依靠的只有官方文档。然而Hertz似乎因为历史原因,之前不支持Windows,连官方文档里都没有提到一些Windows下使用会出现的问题,网上的教程大多是Linux环境,完全没有提到Windows会出现的一些问题.本人也是踩坑了近两天,特开此文以记录,让大家能够脱坑。
准备工作
这个部分本来在你安装go的时候就应该做好了,但是网上众说纷纭,或许是因为版本的问题,这里我给出一个方案,这个方案可能有冗余,但一定不会出错。
- 安装Go,这个去官网就可以了。
- 配置环境变量,这个很重要。 有两个东西,一个叫GOROOT,这个就是你Go在你电脑上安装的地方。比如我的就是D:\own\idi_soft\idi_development\idi_cores\go。 还有一个叫做GOPATH,注意这个GOPATH可不是GOROOT下的bin目录,而是由你自己决定。也就是说是你以后GO的工作区。比如我的就设置在D:\own\idi_soft\idi_development\codes\projects\GoWorks。 然后,在GoWorks(以你自己名字为准)下再创建三个文件夹,分别叫做bin、pkg、src。以后你的项目正常情况下都要创建在src之下。 除此之外,你还要在PATH变量下创建 $GOPATH\bin。
Hertz快速开始
因为一些特殊原因,好像现在不容易看到Hertz的官方文档。所以我就搬运一下,在这一步可以直接跟着官方文档做,不会遇到问题(过了这一步后面就全是问题了) 创建一个项目,然后main.go:
package main
import (
"context"
"github.com/cloudwego/hertz/pkg/app"
"github.com/cloudwego/hertz/pkg/app/server"
"github.com/cloudwego/hertz/pkg/common/utils"
"github.com/cloudwego/hertz/pkg/protocol/consts"
)
func main() {
h := server.Default()
h.GET("/ping", func(c context.Context, ctx *app.RequestContext) {
ctx.JSON(consts.StatusOK, utils.H{"message": "pong"})
})
h.Spin()
}
这里你会遇到一个问题对吧,你粘贴完import里面全是报错。正常的别着急 然后你需要初始化go模块 终端
go mod init
如果你是用Goland直接创建出来的项目那它就自带一个go.mod,你就不需要这一步,反正你就保证你的项目里要有一个可用的go.mod文件就可以了. 然后
go mod tidy
这个命令可厉害,会自动帮你把缺的东西都下载并且整合好. 这里也可能有一个问题,就是你下载不下来import里面那些东西. 解决办法:
打开设置,
把图中选项勾上,然后把你的GOPROXY填到环境里.
go env 命令可以查看你的go环境,里面有GOPROXY.
然而这里又又分支出一个问题,如果你还是不行,就是你那个GOPROXY不行.给他设置成国内的
go env -w GOPROXY=https://goproxy.cn
然后启动你的项目就可以了.成功的话你访问 http://127.0.0.1:8888/ping 就可以得到一个返回信息.
Protobuf准备
- 你可能不知道什么是Protobuf,我也不知道,但是现在比较流行这个所以你就要会,我个人觉得可以粗浅的把他暂时当作是json的一个同事.之前json用很多对吧,前后端统一格式都传递json.然后这个protobuf就是牺牲一点可读性但是换取更高效率的一种数据交换格式.
- 你需要下载Protobuf,记住你下载在哪里了以后有用,比如我下载在D:\own\idi_soft\idi_development\idi_cores\protobuf\protoc-24.1-win64 然后你要把D:\own\idi_soft\idi_development\idi_cores\protobuf\protoc-24.1-win64\bin加到path里面.
Hz自动生成代码
Hz可以根据protobuf自动生成代码. 之前说过你的项目都在src之下,但如果你要用hz,那你项目就不要创建在/src下,你创建在\src\github.com\cloudwego下面,这点在官方文档里说过,如果你的代码在GOPATH下面你就需要额外创建两个文件夹.
基于 protobuf IDL 创建项目
new: 创建一个新项目
-
在当前目录下创建 protobuf idl 文件
- 为在 protobuf 中支持 api 注解,请在使用了注解的 proto 文件中,import 下面的文件
- 如果想自行拓展注解的使用,请不要以"5"作为序号的开头,避免出现冲突。例如 “optional string xxx = 77777;”
// idl/api.proto; 注解拓展 syntax = "proto2"; package api; import "google/protobuf/descriptor.proto"; option go_package = "/api"; extend google.protobuf.FieldOptions { optional string raw_body = 50101; optional string query = 50102; optional string header = 50103; optional string cookie = 50104; optional string body = 50105; optional string path = 50106; optional string vd = 50107; optional string form = 50108; optional string go_tag = 51001; optional string js_conv = 50109; } extend google.protobuf.MethodOptions { optional string get = 50201; optional string post = 50202; optional string put = 50203; optional string delete = 50204; optional string patch = 50205; optional string options = 50206; optional string head = 50207; optional string any = 50208; optional string gen_path = 50301; optional string api_version = 50302; optional string tag = 50303; optional string name = 50304; optional string api_level = 50305; optional string serializer = 50306; optional string param = 50307; optional string baseurl = 50308; } extend google.protobuf.EnumValueOptions { optional int32 http_code = 50401; }Copy
主 idl 定义:
// idl/hello/hello.proto syntax = "proto3"; package hello; option go_package = "hertz/hello"; // 这个名字按你自己的来,你的项目名叫douyin,你就改成douyin/hello import "api.proto"; message HelloReq { string Name = 1[(api.query)="name"]; } message HelloResp { string RespBody = 1; } service HelloService { rpc Method1(HelloReq) returns(HelloResp) { option (api.get) = "/hello"; } }Copy
-
创建新项目
# 在 GOPATH 外执行,需要指定 go mod 名,如果主 IDL 的依赖和主 IDL 不在同一路径下,需要加入 "-I" 选项,其含义为 IDL 搜索路径,等同于 protoc 的 "-I" 命令 hz new -module example.com/m -I idl -idl idl/hello/hello.proto # 整理 & 拉取依赖 go mod tidyCopy
# GOPATH 下执行,如果主 IDL 的依赖和主 IDL 不在同一路径下,需要加入 "-I" 选项,其含义为 IDL 搜索路径,等同于 protoc 的 "-I" 命令 hz new -I idl -idl idl/hello/hello.proto go mod init # 整理 & 拉取依赖 go mod tidyCopy
-
修改 handler,添加自己的逻辑
// handler path: biz/handler/hello/hello_service.go // 其中 "/hello" 是 protobuf idl 中 go_package 的最后一级 // "hello_service.go" 是 protobuf idl 中 service 的名字,所有 service 定义的方法都会生成在这个文件中 // Method1 . // @router /hello [GET] func Method1(ctx context.Context, c *app.RequestContext) { var err error var req hello.HelloReq err = c.BindAndValidate(&req) if err != nil { c.String(400, err.Error()) return } resp := new(hello.HelloResp) // 你可以修改整个函数的逻辑,而不仅仅局限于当前模板 resp.RespBody = "hello," + req.Name // 添加的逻辑 c.JSON(200, resp) }Copy
-
编译项目
go buildCopy
-
运行项目并测试
运行项目:
./{{your binary}}Copy
测试:
curl --location --request GET 'http://127.0.0.1:8888/hello?name=hertz'Copy
如果返回
{"RespBody":"hello,hertz"},说明接口调通。以上都是官方文档内容我就直接抄过来了,但是你跟着做绝对做不成功. 有几个你可能会碰到的问题:
-
提示你说什么google的包找不到之类的,mod tidy不成功, 参考这个解决办法 (protoc_gen_hertz returns error: exit status 1 · Issue #919 · cloudwego/hertz · GitHub))
-
说你router什么的找不到.你刚创建项目的时候先hz new一下,然后再做他的东西,把 hz new -I idl -idl idl/hello/hello.proto改成hz update ..... 就可以