构建web服务
参考官方教程go-zero安装
//安装goctl插件
go install github.com/zeromicro/go-zero/tools/goctl@latest
//加载go-zero依赖
go get -u github.com/zeromicro/go-zero@latest
zero构建一个http服务器,基于goctl命令创建:
goctl api new demo
在目录下生成一个web服务
在web目录下,etc是web服务的整体配置,一般包括项目名称,主机,端口等;internal是一个web的主体部分,包括路由,接口配置,逻辑部分,参数类型等;web.api是生成web服务的配置文件和grpc远程服务proto文件生成rpc服务器一样,web.api文件是生成控制器也叫接口的配置文件;web.go文件web服务的入口文件,服务器通过改文件启动。
在internal文件夹下,包含配置文件,控制器,逻辑部分,参数集等。需要加入自己的逻辑部分只需要修改logic目录下的文件即可。
根据官网的提示在logic.go文件27行添加如下代码:
resp = new(types.Response)
resp.Message = req.Name
切换到web目录下,运行web程序
浏览器输入http://127.0.0.1:8888/from/me
上述步骤实现了基于go-zero的web服务,这个web是基于go的net/http重构的,可能go较为流行的gin框架,go-zero的实现的web和gin还是有很大的区别的。
config.go
文件
用来记载etc文件的yml的配置,具体配置项如下:
svc
目录
该目录的文件将config的配置加载到控制器中。
handler
目录
控制器负责转发路由,在routes.go
中就是路由:
func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
server.AddRoutes(
[]rest.Route{
{
Method: http.MethodGet,
Path: "/from/:name",
Handler: WebHandler(serverCtx),
},
},
)
}
zero的路由不用与gin,其是通过路由注册的方式。在zero中rest
是zero的web对象,rest.RestConf是配置类。
rest.Server
是web容器,包含引擎和路由,提供了众多方法配置路由和引擎。
rest.Route
是一个整体的路由对象,包含请求方法,请求路径和处理逻辑。
AddRoutes
是rest.Server提供的注册路由的方法,其参数是路由对象数组[]rest.Route
。
如上的注册逻辑,路由地址和方法以及处理逻辑均被注册到web容器中。
//路由对象也可分离出来
var routeList []rest.Route = []rest.Route{
//rest.Route
//...
}
路由的处理函数还有一个参数,来自svc
目录,该结构体封装了rest.RestConf
也就是web容器的配置类。
转到路由处理函数,该配置类直到调用逻辑部分才被调用,如下图:
svc.ServiceContext
就是封装了一下config结构体,logx.Logger
是日志,context.Context
是上下文连接,这个才是最重要的,就像gin的gin.Context一样。
这些并不需要开发者完全使用,结构体的多层封装是为了方便扩展,如果需求不高,直接使用默认的即可。
因此,这个封装的
svc.ServiceContext
的配置参数并不是必须的。存在这个参数可以改变对上下文,日志更改,不存在就是使用框架默认的。
那么一个处理函数必须包含那些必要的条件呢?接下来从一个函数来解析。
看到goctl生成的标准路由处理函数,之前已经说明了不需要svc.ServiceContext
参数,那么http.HandlerFunc
返回值函数就是必须的了。
看到http.HandlerFunc
的源码其本身是一个函数类型,且携带了两个参数,一个响应一个请求。
那么就可以得到结论,路由处理函数是返回类型为http.HandlerFunc
的任意函数。
只要自定义的函数满足上述条件,就可以当做路由处理函数注册到路由的rest.Route
对象。
// 自定义处理函数
func MyHandler() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
httpx.OkJsonCtx(r.Context(), w, "hello")
}
}
//路由注册
func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
server.AddRoutes(
[]rest.Route{
{
Method: http.MethodGet,
Path: "/from/:name",
Handler: WebHandler(serverCtx),
},
{
Method: http.MethodGet,
Path: "/hello",
Handler: MyHandler(),
},
},
)
}
启动web服务器,在浏览器端访问
另外,如下图所示查看处理函数的参数,响应参数和请求参数。
显然对于http的请求与响应操作。但是官方使用了httpx
这个库,转到该库可以看到内部函数大多都包含http.ResponseWriter
对其进一步封装。
开发者可以使用http.ResponseWriter
元素返回参数,也可以使用httpx
提供的方法返回数据。后者的优势是可以直接返回结构体不用在序列化操作。
// 返回短文
func ArticleController() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
//定义结构体
type Article struct {
Str string
}
art := Article{
"开发者可以使用http.ResponseWriter元素返回参数,也可以使用httpx提供的方法返回数据。后者的优势是可以直接返回结构体不用在序列化操作。",
}
httpx.OkJson(w, art)
}
}
路由处理函数可以模块化并自己封装,实现定制的服务。
最后就是api
文件了,api文件是goctl插件一键化生成一个控制的配置文件,通过api的一些简单的配置可以直接生成一个控制,开发者只需要编写逻辑部分,非常方便。
有兴趣的可以了解api语法,使用自动生成工具会快捷很多。