Go小课03:Gin Simple Demo解读

图片

1、概述

一、简介
  • Go官方为了支持Web开发,提供了net/http工具包;可是在实际项目中,团队仍是会选择更加高效,更便捷的Web框架,如GinEcho,Beego等;
  • 在这些团队中,不少团队选择了Gin这个框架,它在net/http 的基础上作了优化;对比其余主流框架,它更好的性能更快的路由
二、Gin的优势
  • 快速:基于Radix树的路由,性能很是强大。git

  • 支持中间件:内置许多中间件,如Logger,Gzip,Authorization等。github

  • 崩溃恢复:能够捕捉panic引起的程序崩溃,使Web服务能够一直运行。web

  • JSON验证:能够验证请求中JSON数据格式。api

  • 路由分组:支持路由分组(RouteGroup),能够更方便组织路由。数组

  • 错误管理机制:能够收集程序中的错误bash

  • 多种数据渲染方式:支持HTMLJSONYAMLXML等数据格式的响应。服务器

  • 扩展性:很是简单扩展中间件。数据结构

  • 数据验证器:支持数据验证器且能够自定义。框架

三、Gin Simple Demo
package main

import (
	"github.com/gin-gonic/gin"
    "net/http"
)

func setupRouter() *gin.Engine {

	r := gin.Default()
	// Ping test
	r.GET("/ping", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"status" : 0,
			"msg" 	 : "success",
			"data"   :  gin.H {
				"content" : "pong",
			},
		})
	})
	return r
}

func main() {
   r := setupRouter()
   r.Run() 
}
复制代码

2、Gin Simple Demo 解读

从Demo Code能够看出,使用Gin的体验很是顺滑,定义处理Web请求就四步:导入包定义路由编写 Handler监听端口函数

1. 导入包
import "github.com/gin-gonic/gin"
复制代码
2. 定义路由
  • gin.Engine是路由引擎,通常使用gin.Default()方法建立并返回gin.Engine实例.
r := gin.Default() //r默认使用了Logger和Recovery两个中间件
复制代码

说明:能够用gin.New()方法建立并返回一个不包含任何中间件的gin.Engine实例

3. 编写 Handler

经过默认路由,咱们能够建立处理HTTP请求的方法,示例中使用GET方法:

// Ping test
r.GET("/ping", func(c *gin.Context) {
	c.JSON(http.StatusOK, gin.H{
			"status" : 0,
			"msg" 	 : "success",
			"data"   :  gin.H {
				"content" : "pong",
		},
	})
})
复制代码
  • Get方法底层实现是调用RouterGrouphandle方法, 请求的处理是使用HandlerFunc类型方法
// GET is a shortcut for router.Handle("GET", path, handle).
func (group *RouterGroup) GET(relativePath string, handlers ...HandlerFunc) IRoutes {
	return group.handle("GET", relativePath, handlers)
}

// HandlerFunc defines the handler used by gin middleware as return value.
type HandlerFunc func(*Context) 复制代码
  • 说明:Gin支持全部通用的HTTP请求方法,如GET,POST,PUT,PATCH,OPTIONS,HEAD,DELETE
4. 监听端口
  • 定义好请求以后,使用Run()方法即可监听端口,开始接受HTTP请求,若是Run()方法没有传入参数的话,则默认监听8080端口。
r.Run() 
复制代码
  • Run方法的底层实现关键是:http.ListenAndServe,其中:http来自net/http包。
func (engine *Engine) Run(addr ...string) (err error) {
	defer func() { debugPrintError(err) }()

	address := resolveAddress(addr)
	debugPrint("Listening and serving HTTP on %s\n", address)
	//
	err = http.ListenAndServe(address, engine)
	return
}
复制代码

3、Gin中重要数据结构

​ 在Gin Simple Demo Code中,咱们发现了三个重要的Go数据结构:gin.Enginegin.Contextgin.RouterGroup

一、gin.Engine
  • gin.Engine 是框架的入口;咱们经过 Engine 对象来定义服务路由信息、组装插件、运行服务,整个 Web 服务的都是由它来驱动的。
// Engine is the framework's instance, it contains the muxer, middleware and configuration settings.
// Create an instance of Engine, by using New() or Default()
type Engine struct {
	RouterGroup
	
	//....
}
复制代码
  • gin.Engine本质是对内置的 HTTP 服务器的包装,让它使用起来更加便捷。
  • gin.Default() 函数会生成一个默认的 Engine 对象,里面包含了 2 个默认的经常使用插件,分别是 Logger 和 Recovery,Logger 用于输出请求日志,Recovery 确保单个请求发生 panic 时记录异常堆栈日志,输出统一的错误响应(推荐使用)。
func Default() *Engine {
   debugPrintWARNINGDefault()
   engine := New()
   engine.Use(Logger(), Recovery())
   return engine
}
复制代码
  • gin.New()函数会生成一个默认的 Engine 对象,不包含任何中间件的gin.Engine实例。
二、gin.Context
  • 请求的上下文信息对象,它是全部请求Handler的入口参数。gin.Context的结构定义以下:
// Context容许咱们在中间件之间传递变量,管理流程,验证请求的JSON,并返回JSON
type Context struct {
	//请求对象
	Request   *http.Request
    
    // 用来响应 
    writermem responseWriter
	Writer    ResponseWriter
 	// URL里面的参数,好比:/xx/:id 
	Params   Params
	
     // 参与的处理者(中间件 + 请求处理者列表)
    handlers HandlersChain
    // 当前处理到的handler的下标
    index    int8

	fullPath string
	
    // Engine单例
	engine *Engine

	// 在context能够设置的值
	Keys map[string]interface{}

	// 一系列的错误
	Errors errorMsgs

	//为内容协商定义一组手动接受的格式。
	Accepted []string

	// queryCache use url.ParseQuery cached the param query result from c.Request.URL.Query()
	queryCache url.Values

	// formCache use url.ParseQuery cached PostForm contains the parsed form data from POST, PATCH,
	// or PUT body parameters.
	formCache url.Values
}
复制代码
  • Context这个上下文对象不是每次生成,而是从对象池里面取出来的;而请求的真正处理核心在handleHTTPRequest函数中。
  • handleHTTPRequest函数中的核心逻辑:根据请求方法和请求的URI,找到并调用 处理的函数数组(包括咱们定义的处理函数,还有中间层的处理函数)。
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {

	// 从对象池中获取一个context对象
	c := engine.pool.Get().(*Context)

	// 初始化上下文对象,由于从对象池取出来的数据,有脏数据,故要初始化。
	c.writermem.reset(w)
	c.Request = req
	c.reset()

    //处理web请求 (http请求处理)
	engine.handleHTTPRequest(c)

	//将Context对象扔回对象池了
	engine.pool.Put(c)
}
复制代码
三、gin.RouterGroup
  • RouterGroup是路由分组,是对路由树的包装,全部的路由规则最终都是由它来进行管理。Engine 结构体继承了 RouterGroup ,因此 Engine 直接具有了 RouterGroup 全部的路由管理功能。
// RouterGroup is used internally to configure router, a RouterGroup is associated with
// a prefix and an array of handlers (middleware).
type RouterGroup struct {
	Handlers HandlersChain
	basePath string
	engine   *Engine
	root     bool
}

// HandlersChain defines a HandlerFunc array.
type HandlersChain []HandlerFunc
复制代码
  • RouteGroup 对象中主要包括:basePath(前缀路径)、Engine 指针Handlers(处理函数数组)。

  • RouterGroup 实现了 IRouter 接口定义的一系列路由方法;这些方法最终都是经过调用 Engine.addRoute 方法将请求处理器挂接到路由树中。

  • RouterGroup 内部有一个前缀路径属性,它会将全部的子路径都加上这个前缀再放进路由树中。有了这个前缀路径,就能够实现 URL 分组功能。Engine 对象内嵌的 RouterGroup 对象的前缀路径是 /,它表示根路径。RouterGroup 支持分组嵌套,使用 Group 方法就可让分组下面再挂分组。

    v1 := r.Group("/api/v1")
    {
    	v1.POST("/submit",submit)
    	v1.GET("/list",list)
    }
    // Engine对象中RouterGroup对象是第一层分组(根分组),v1是根分组的子分组。
    复制代码
四、gin.H
  • gin.H 是 map[string]interface{} 的一个快捷名称.
type H map[string]interface{}
复制代码
相关文章
相关标签/搜索