Gone框架介绍30 - 使用`goner/gin`提供Web服务

gone是可以高效开发Web服务的Golang依赖注入框架

github地址:https://github.com/gone-io/gone

文档地址:https://goner.fun/zh/

使用goner/gin提供Web服务

文章目录

注册相关的Goners

这里我们编写一个Priest函数,用于注册相关的Goners。

go 复制代码
package main
import (
	"github.com/gone-io/gone"
	"github.com/gone-io/gone/goner"
)

// 用于注册Goners的Priest函数
func Priest(cemetery gone.Cemetery) error {
	//注册gin相关的Goners
	_ = goner.GinPriest(cemetery)

    //TODO: 注册其他的Goners
	return nil
}

func main() {
    // 在main函数中使用Priest函数启动服务
	gone.Serve(Priest)
}

将上面代码保存为main.go,,代码已经能够正常运行起来了,运行中代码会监听本地8080端口,但是所有的请求都是返回404。

编写Controller挂载路由

为了提供服务,而不只是返回404,我们需要编写一个Controller,挂载路由。

新建文件controller.go,编写如下代码:

go 复制代码
// NewController controller 的构造函数
func NewController() gone.Goner {
	return &controller{}
}

type controller struct {
	gone.Flag
	root gone.RouteGroup `gone:"*"` // 根路由组
}

func (ctr *controller) Mount() gone.GinMountError {
	ctr.root.GET("/ping", func() string {
		return "hello gone"
	})
	return nil
}

然后,在main.go文件Priest函数中添加注册Controller的代码:

go 复制代码
	//注册Controller
	cemetery.Bury(NewController())

再次运行代码:go run .,使用curl命令访问localhost:8080/ping,返回{"code":0,"data":"hello gone"}

上面代码中,controller通过实现方法Mount() gone.GinMountError成为gin.Controllergoner/gin启动过程中会自动调用Mount()方法;我们需要再该方法中挂载我们希望处理的路由。

为此,我们需要在controller上添加一个gone.RouteGroup类型的root字段,使用gone:"*"标记为依赖注入;Gone会将代表根路由的gone.RouteGroup装配到root属性上。gone.RouteGroup是一个接口,定义了用于挂载路由的GETPOST等方法,下面是其定义:

go 复制代码
type IRoutes interface {
	Use(...HandlerFunc) IRoutes

	Handle(string, string, ...HandlerFunc) IRoutes
	Any(string, ...HandlerFunc) IRoutes
	GET(string, ...HandlerFunc) IRoutes
	POST(string, ...HandlerFunc) IRoutes
	DELETE(string, ...HandlerFunc) IRoutes
	PATCH(string, ...HandlerFunc) IRoutes
	PUT(string, ...HandlerFunc) IRoutes
	OPTIONS(string, ...HandlerFunc) IRoutes
	HEAD(string, ...HandlerFunc) IRoutes
}

type IRouter interface {
	IRoutes

	GetGinRouter() gin.IRouter

	Group(string, ...HandlerFunc) RouteGroup

	LoadHTMLGlob(pattern string)
}

// RouteGroup route group, which is a wrapper of gin.RouterGroup, and can be injected for mount router.
type RouteGroup interface {
	IRouter
}

路由处理函数

通过RouteGroup定义可以看到,GETPOST等用于挂载路由的函数,都可以接收多个HandlerFunc参数。HandlerFunc要求是一个函数,这里称为路由处理函数

路由处理函数,可以接收多个参数,也可以返回多个值;一般返回两个值,一个正常值 和 一个 error 值,如下:

go 复制代码
func processRoute(ctx *gin.Context) (string, error) {
    return "hello gone", nil
}

正常值的类型可以为 golang 的简单类型(int、string、float 等)、结构体、指针、接口、数组、slice、map 等;还可以返回 io.Readerchan any两种特殊类型。

io.Reader

通过io.Reader可以返回任意的数据,比如返回一个文件:

go 复制代码
	ctr.root.GET("/file", func() (io.Reader, error) {
		return os.Open("main.go")
	})

重启后,用curl测试:curl -o main.go http://localhost:8080/file,可以下载到main.go文件。

特别提醒一下,将http://localhost:8080/file输入到浏览器地址栏并不会触发下载,而是直接显示了文件内容,这是因为返回的是文本内容,并且又缺少触发下载的Header:Content-Disposition

chan any

通过返回chan any,可以方便的实现一个SSE服务。

go 复制代码
	type Info struct {
		Msg   string `json:"msg"`
		Index int    `json:"index"`
	}
	ctr.root.GET("/sse", func() chan any {
		ch := make(chan any)
		go func() {
			defer close(ch) //注意关闭channel

			for i := 0; i < 3; i++ {
				time.Sleep(time.Second)
				ch <- Info{
					Index: i,
					Msg:   "hello gone",
				}
			}
		}()
		return ch
	})

Mount 函数中添加上面代码,然后重启服务。使用curl测试:curl http://localhost:8080/sse,可以得到如下输出(每秒收到一个event):

log 复制代码
event: data
data: {"msg":"hello gone","index":0}

event: data
data: {"msg":"hello gone","index":1}

event: data
data: {"msg":"hello gone","index":2}

event: done

HTTP请求参数注入

路由处理函数的参数,支持依赖注入。

  1. 支持注册到Gone的Goners类型直接作为参数,例如以gone.Logger类型作为参数:
go 复制代码
	ctr.root.GET("inject", func(logger gone.Logger) string {
		logger.Infof("inject")
		return "inject"
	})
  1. 支持以*gin.Context*gone.Context类型作为参数:

gone.Context 是对 gin.Context的封装,兼容gin.Context

go 复制代码
	ctr.root.GET("inject", func(logger gone.Logger, ctx *gone.Context) string {
		logger.Infof("inject")
		logger.Infof("hots: %s", ctx.Request.Host)

		return "inject"
	})
  1. 支持参数为一个匿名结构体,在结构体上做依赖注入标记:
go 复制代码
	ctr.root.GET("inject", func(logger gone.Logger, ctx gone.Context, in struct {
		selects []int       `gone:"http,query=select"` //HTTP参数注入:表示取query参数中的select作为数组,要求值可以转为int类型
		logger2 gone.Logger `gone:"*"`                 //注入gone.Logger类型的logger
	}) string {
		logger.Infof("inject")
		logger.Infof("hots: %s", ctx.Request.Host)
		logger.Infof("selects: %v", in.selects)

		return "inject"
	})

更多关于 HTTP请求参数注入 只是,请参考:HTTP 注入说明

配置项

goner/gin支持通过配置,改变默认行为;关于配置的读取和配置文件的格式参考 配置读取

例子,将端口改为 8000

创建配置文件:

bash 复制代码
mkdir config
echo 'server.port=8000' > config/default.properties

更多配置项

配置项 说明 类型 默认值
server.port 监听端口 int 8080
server.host 监听地址 string 0.0.0.0
server.mode gin mode,可选值为:debug、test、release string release
server.html-tpl-pattern 用于gin.LoadHTMLGlob加载模版路径 string <空>
server.health-check 配置一个路径用于监控检查 string <空>
server.log.show-access-log 是否打印访问日志 bool true
server.log.show-request-time 是否在日志中打印请求耗时 bool true
server.log.data-max-length 日志数据最大长度,超过该长度会截断,0为不限制 int 0
server.proxy.stat 代理耗时统计 bool false
server.return.wrapped-data 使用{"code": ${code}, "msg": ${msg}, "data": ${data} }封装数据 bool true

更多例子

跳转 快速开始

相关推荐
YGY Webgis糕手之路2 小时前
Cesium 快速入门(七)材质详解
前端·经验分享·笔记·vue·web
YGY Webgis糕手之路5 小时前
Cesium 快速入门(八)Primitive(图元)系统深度解析
前端·经验分享·笔记·vue·web
YGY Webgis糕手之路6 小时前
Cesium 快速入门(四)相机控制完全指南
前端·经验分享·笔记·vue·web
YGY Webgis糕手之路6 小时前
Cesium 快速入门(六)实体类型介绍
前端·经验分享·笔记·vue·web
YGY Webgis糕手之路7 小时前
Cesium 快速入门(一)快速搭建项目
前端·经验分享·笔记·vue·web
阿祥~7 小时前
FISCO BCOS Gin调用WeBASE-Front接口发请求
区块链·gin·fisocbocs
白山云北诗7 小时前
云原生环境 DDoS 防护:容器化架构下的流量管控与弹性应对
云原生·架构·web·ddos·网站安全·网络攻击·安全防护
OEC小胖胖16 小时前
性能优化(一):时间分片(Time Slicing):让你的应用在高负载下“永不卡顿”的秘密
前端·javascript·性能优化·web
旧时光巷17 小时前
【Flask 基础 ①】 | 路由、参数与模板渲染
后端·python·零基础·flask·web·模板渲染·路由系统
集成显卡2 天前
Rust 实战三 | HTTP 服务开发及 Web 框架推荐
开发语言·前端·http·rust·web