Gin框架:启动Web服务时,Gin框架做了什么?

公众号:程序员读书,欢迎关注

大家好,在这个系列中,我们从源码的角度来探究一下Gin框架,每一篇文章只专注一个知识点的讲解!

在这篇文章中,我们来探究一下,启动Web服务时,Gin框架做了什么?

Gin启动Web服务的两种方式

使用Gin框架启动一个Web服务器,本质上是创建一个gin.Engine对象的实例,有两种方式。

一是通过New方法创建gin.Engine对象实例:

go 复制代码
 package main
 ​
 import (
   "github.com/gin-gonic/gin"
 )
 ​
 func main() {
   engine := gin.New()
   engine.Run()
 }

二是通过Default方法创建gin.Engine对象实例:

go 复制代码
 package main
 ​
 import (
   "github.com/gin-gonic/gin"
 )
 ​
 func main() {
   engine := gin.Default()
   engine.Run()
 }

创建gin.Engine对象的实例后,调用其Run方法,就这样,一个Web服务器便启动了!

Default和New方法

DefaultNew方法创建的对象有什么不同呢?

通过查看Default方法的源码可以得知,Default方法实际上是调用New方法的:

scss 复制代码
 func Default() *Engine {
   debugPrintWARNINGDefault()
   engine := New()
   engine.Use(Logger(), Recovery())
   return engine
 }

Default方法会调用gin.EngineUse方法设置Logger()Recovery()两个中间件。

gin.Engine对象

gin.Engine对象是gin包下的一个结构体:

go 复制代码
 type Engine struct {
     //路由分组
   RouterGroup
     //当请求以/结尾时,是否重定向,默认为是
   RedirectTrailingSlash bool
   //是否自动修复路径并重定向,默认为否
     RedirectFixedPath bool
   //当请求method不匹配时,是否返回403,默认为否
     HandleMethodNotAllowed bool
     //是否按RemoteIPHeaders属性规则的头部解析客户端IP地址
   ForwardedByClientIP bool
     //是否从原始请求路径中查找参数
   UseRawPath bool
     //是否取消url转义
   UnescapePathValues bool
   //是否移除多余的/
     RemoveExtraSlash bool
   //获取客户端IP的头部字段列表
     RemoteIPHeaders []string
     //信任的平台
   TrustedPlatform string
     //请求内容大小限制,默认为32M
   MaxMultipartMemory int64
     //是否开启http2
   UseH2C bool
     //是否开启回退
   ContextWithFallback bool
     //HTML模板动态代码分隔符
   delims           render.Delims
     //安全json前缀
   secureJSONPrefix string
     //HTML模板渲染器
   HTMLRender       render.HTMLRender
   //HTML模板处理函数
     FuncMap          template.FuncMap
   //未匹配路由时的处理函数
     allNoRoute       HandlersChain
   //未匹配方法时的处理函数
     allNoMethod      HandlersChain
   //未匹配路由时的处理函数
     noRoute          HandlersChain
   //未匹配方法时的处理函数
     noMethod         HandlersChain
   //缓存池
     pool             sync.Pool
     //路由树
   trees            methodTrees
   //参数个数
     maxParams        uint16
   //路径个数
   maxSections      uint16
     //信任代理列表
   trustedProxies   []string
     //信任的ip列表
   trustedCIDRs     []*net.IPNet
 }

Engine结构有非常多的属性,我们在后面的源码学习中再详细讲解。

这里对于Engine对象,我们先有两个基本的认识:

  • 我们看到Engine对象拥有路由分组RouteGroup对象,因此可以说Engine对象是所有路由的根路由。
  • Engine对象还实现了http.Handler接口:
go 复制代码
 type Handler interface {
   ServeHTTP(ResponseWriter, *Request)
 }

因此可以把Engine对象实例作为net/http中的路由复用器,所以,我们还可以这样启动Web服务器:

css 复制代码
 engine := gin.New()
 http.ListenAndServe(":8080", engine)

实际上,Run方法底层就是调用http.ListenAndServe方法。

Run方法

创建gin.Engine对象实例之后,调用Run()方法启动Web服务器时,也可以传一个参数作为端口号:

scss 复制代码
 Run(":3000")

在没有设置端口号时,也可以通过环境变量PORT设置端口号:

go 复制代码
 $ PORT=3000 && go run main.go

如果没有传环境变量或者给Run()方法设置参数,则默认设置为监听8080端口,这些从Run()方法的源码都可以看得出来:

go 复制代码
 //gin.go第367行起
 func (engine *Engine) Run(addr ...string) (err error) {
   defer func() { debugPrintError(err) }()
 ​
   if engine.isUnsafeTrustedProxies() {
     debugPrint("[WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.\n" +
       "Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.")
   }
 ​
   address := resolveAddress(addr)
   debugPrint("Listening and serving HTTP on %s\n", address)
   err = http.ListenAndServe(address, engine.Handler())
   return
 }
 ​
 //utils.go第141行起
 func resolveAddress(addr []string) string {
   switch len(addr) {
   case 0:
     if port := os.Getenv("PORT"); port != "" {
       debugPrint("Environment variable PORT="%s"", port)
       return ":" + port
     }
     debugPrint("Environment variable PORT is undefined. Using port :8080 by default")
     return ":8080"
   case 1:
     return addr[0]
   default:
     panic("too many parameters")
   }
 }

从上面的源码可以看到Run方法的参数虽然是可变长的,但resolveAddress()函数会检查传入参数的个数,当向Run方法传入多个参数是会触发panic

小结

gin.Engine对象是Gin框架的入口,该对象有非常多的属性,另外,gin.Engine对象实现了http.Handler接口,可以与net/http完美兼容,调用gin.EngineRun()方法可以启动一个Web服务。

相关推荐
㳺三才人子6 小时前
初探 Flask
后端·python·flask·html
星栈独行6 小时前
我在 Rust 全栈项目里用 JWT 做无状态认证
开发语言·后端·rust·前端框架·开源·github·web
Java爱好狂.6 小时前
Java程序员体系化学习路线(2026最新版)
java·后端·java面试·java架构师·java程序员·java八股文·java学习路线
陈随易7 小时前
Redis 8.8发布,一定要更新
前端·后端·程序员
装不满的克莱因瓶7 小时前
SpringBoot 如何将 lib 目录中jar包打包进最终的jar包里面
spring boot·后端·maven·jar·mvn
ltl8 小时前
Transformer 原论文实验结果:为什么 28.4 BLEU 足以改写路线图
后端
excel8 小时前
为什么我推荐使用 Termius:现代 SSH 工具的完整体验
前端·后端
卷毛的技术笔记9 小时前
Java后端硬核实战:用Spring AI Alibaba+Redis给LLM装上“超强记忆中枢”
java·人工智能·redis·后端·spring·ai·系统架构
IT_陈寒10 小时前
Java的Optional差点让我掉坑里,这几个坑你别踩
前端·人工智能·后端
子兮曰10 小时前
Harness 驾驭工程深度教程:从 AGENTS.md 到全链路 AI 编码基础设施
前端·后端·ai编程