
2024年在线市场平台的11大最佳支付解决方案
gin 是golang 中比较流行的框架,很多系统都是在该框架下开发的,这个框架给我的感觉像是Flask在python中的位置,基础的功能都有,但是如果想要很好的使用,还需要开发很多自己的功能与中间件,在看过不少的教程以后,想要记录一下学习过程中遇到的各种问题。
本系列简单的实现了一些做后台服务的能用方法,如获取参数,数据库查询等操作,项目的整体还谈不上架构,顶多算是个quick start, 目录结构也不那么讲究,因为初学,所以肯定会有很多问题。以后再一点点地实践一点点地修改吧。
第一篇,简单一些,先把框架搭起来,写个 hello world 出来。
项目基于go module 方式,在一个空目录中运行 go mod init gintest
初始化项目,go 会自动生成一个go.mod 文件
在go.mod 文件中添加gin
module gintest
go 1.15
require (
github.com/gin-gonic/gin v1.7.4
)
之后使用go mod download
命令下载。
或者在项目目录中直接运行 go get github.com/gin-gonic/gin@v1.7.4
命令,也会下载gin包,并且会自动添加到go.mod 文件中。
新建一个server.go 文件,写入以下代码
package main
import "github.com/gin-gonic/gin"
func main() {
r := gin.Default()
r.GET("/", func(c *gin.Context) {
c.JSON(200, gin.H{
"Msg":"Hello World",
})
})
r.Run(":8080")
}
代码很简单,运行go run server.go
则会在8080端口启动一个http服务,使用浏览器访问 http://127.0.0.1:8080/
则会返回json的数据
{
Msg: "Hello world"
}
上面代码中,使用gin.Default()
创建一个默认的gin应用,这个应用底层初始化了很多设置,这里就先不深入探索了。
这里就注册了一个路由,/
,它的处理由一个匿名函数来处理, gin 中的GET方法的定义为
// GET is a shortcut for router.Handle("GET", path, handle).
func (group *RouterGroup) GET(relativePath string, handlers ...HandlerFunc) IRoutes {
return group.handle(http.MethodGet, relativePath, handlers)
}
handler 为处理方法,该方法的定义为
type HandlerFunc func(*Context)
所以这里需要一个参数为(*Context) 的函数,上面的代码中使用
func(c *gin.Context) {
c.JSON(200, gin.H{
"Msg":"Hello World",
})
}
这个匿名函数来处理 /
的GET请求。
这里还可以定义POST、DELETE、PUT 等方法,这样可以很方便的编写restful 风格的API,
r.POST("/", func(c *gin.Context) {
c.JSON(200, gin.H{
"Msg":"Hello world POST",
})
})
默认的404处理,会打印 404 not found,更多的时候,我们想自定义404页面的处理,这时可以通过设置r.NoRoute
方法来实现
r.NoRoute(func(c *gin.Context) {
c.JSON(404, gin.H{
"Msg": "The page not found",
})
})
这时在访问一个不存在的路由时会展示自定义的内容。
很多时候,我们是有这样的需求,访问的路由前面都有统一的前缀,如/api/v1
, 或者/user
,当然可以在定义路由的时候都统一写上前缀,但是这种方式,如果后期修改了前缀将要改好多地方。这里可以使用路由组的概念。
func main() {
r := gin.Default()
r.GET("/", func(c *gin.Context) {
c.JSON(200, gin.H{
"Msg": "Hello world",
})
})
apiv1 := r.Group("/api/v1")
{
apiv1.GET("/", func(c *gin.Context) {
c.JSON(200, gin.H{"msg": "hello api v1"})
})
}
r.Run(":8080")
}
以上代码,定义了一个路由组,/api/v1
, 之后又会在该路由组下定义相应的处理方法,这里区分 http://127.0.0.1:8080/
这个url 返回 "Msg": "Hello world"
, /api/v1/
这个路由返回 "msg": "hello api v1"
上面的路由的处理类都是使用匿名函数,处理的逻辑比较简单的话,可以这么写,但是还是不建议写个匿名函数来处理,之后随着项目越来越大,这里的路由定义会越来越多,如果还有大量的匿名函数的话,看着就会比较乱。
这里我们可以将处理handler 进行封装。
先创建一个handlers 的文件夹,写入以下代码
package handlers
import "github.com/gin-gonic/gin"
type ApiV1 struct {
}
func (ApiV1) Get(c *gin.Context) {
c.JSON(200, gin.H{"msg": "handlers get request!"})
}
这里定义了一个ApiV1的结构体, 之后定义了一个Get 方法,然后在入口 server.go 文件中,修改原来的代码,
func main() {
r := gin.Default()
apiv1_h := handlers.ApiV1{}
r.GET("/", func(c *gin.Context) {
c.JSON(200, gin.H{
"Msg": "Hello world",
})
})
apiv1 := r.Group("/api/v1")
{
apiv1.GET("/", apiv1_h.Get)
}
r.Run(":8080")
}
使用apiv1_h := handlers.ApiV1{}
初始化一个ApiV1的结构体对象,在之后路由定义的时候,就可以直接使用该对象的Get方法,最好将相同前缀的放入一个括号中{}
,方法查看
{
apiv1.GET("/", apiv1_h.Get)
}
这里注意,处理handler 为 apiv1_h.Get
, 而不是 apiv1_h.Get(c, *gin.Context)
上面的代码都是以r.run(":8080")
的方式启动服务,但是有时候我们希望做一些个性化的设置,如一些读写超时,当然也可以调用gin.New()
方法中得到的对象中进行设置,也可以直接使用http.Server
中定义。
func main() {
r := gin.Default()
apiv1_h := handlers.ApiV1{}
apiv1 := r.Group("/api/v1")
{
apiv1.GET("/", apiv1_h.Get)
}
s := &http.Server{
Addr: ":8080",
Handler: r,
ReadTimeout: 10*time.Second,
WriteTimeout: 10*time.Second,
}
err := s.ListenAndServe()
if err != nil {
return
}
}
上面的代码在处理请求的时候,都是返回json数据,由于现在主流开发使用前后端分离的模式,所以这里不太使用html 模板的方式返回数据了。
当使用第三方登录的时候,全牵扯到网页跳转,网页跳转也非常简单, 修改apiv1.go 文件
package handlers
import "github.com/gin-gonic/gin"
type ApiV1 struct {
}
func (*ApiV1) Get(c *gin.Context) {
c.Redirect(301, "https://www.baidu.com")
}
这样在方法的对应的路由的时候,就会跳转到百度了。
这里要注意,状态码必须处理300-308之间,否则会报错
func (r Redirect) Render(w http.ResponseWriter) error {
if (r.Code < http.StatusMultipleChoices || r.Code > http.StatusPermanentRedirect) && r.Code != http.StatusCreated {
panic(fmt.Sprintf("Cannot redirect with status code %d", r.Code))
}
http.Redirect(w, r.Request, r.Location, r.Code)
return nil
}
gin 框架的基本搭建先记录到这里,之后会介绍各种请求参数的获取与校验。
文章转自微信公众号@序语程言