1 Engine 主引擎
1. Gin 框架知识地图
思维导图的地址:https://www.processon.com/mindmap/64881fc0b268c21e18a94548

2. 主要字段有哪些
2.1. 全部字段
type Engine struct {
RouterGroup
// RedirectTrailingSlash enables automatic redirection if the current route can't be matched but a
// handler for the path with (without) the trailing slash exists.
// For example if /foo/ is requested but a route only exists for /foo, the
// client is redirected to /foo with http status code 301 for GET requests
// and 307 for all other request methods.
RedirectTrailingSlash bool
// RedirectFixedPath if enabled, the router tries to fix the current request path, if no
// handle is registered for it.
// First superfluous path elements like ../ or // are removed.
// Afterwards the router does a case-insensitive lookup of the cleaned path.
// If a handle can be found for this route, the router makes a redirection
// to the corrected path with status code 301 for GET requests and 307 for
// all other request methods.
// For example /FOO and /..//Foo could be redirected to /foo.
// RedirectTrailingSlash is independent of this option.
RedirectFixedPath bool
// HandleMethodNotAllowed if enabled, the router checks if another method is allowed for the
// current route, if the current request can not be routed.
// If this is the case, the request is answered with 'Method Not Allowed'
// and HTTP status code 405.
// If no other Method is allowed, the request is delegated to the NotFound
// handler.
HandleMethodNotAllowed bool
// ForwardedByClientIP if enabled, client IP will be parsed from the request's headers that
// match those stored at `(*gin.Engine).RemoteIPHeaders`. If no IP was
// fetched, it falls back to the IP obtained from
// `(*gin.Context).Request.RemoteAddr`.
ForwardedByClientIP bool
// AppEngine was deprecated.
// Deprecated: USE `TrustedPlatform` WITH VALUE `gin.PlatformGoogleAppEngine` INSTEAD
// #726 #755 If enabled, it will trust some headers starting with
// 'X-AppEngine...' for better integration with that PaaS.
AppEngine bool
// UseRawPath if enabled, the url.RawPath will be used to find parameters.
UseRawPath bool
// UnescapePathValues if true, the path value will be unescaped.
// If UseRawPath is false (by default), the UnescapePathValues effectively is true,
// as url.Path gonna be used, which is already unescaped.
UnescapePathValues bool
// RemoveExtraSlash a parameter can be parsed from the URL even with extra slashes.
// See the PR #1817 and issue #1644
RemoveExtraSlash bool
// RemoteIPHeaders list of headers used to obtain the client IP when
// `(*gin.Engine).ForwardedByClientIP` is `true` and
// `(*gin.Context).Request.RemoteAddr` is matched by at least one of the
// network origins of list defined by `(*gin.Engine).SetTrustedProxies()`.
RemoteIPHeaders []string
// TrustedPlatform if set to a constant of value gin.Platform*, trusts the headers set by
// that platform, for example to determine the client IP
TrustedPlatform string
// MaxMultipartMemory value of 'maxMemory' param that is given to http.Request's ParseMultipartForm
// method call.
MaxMultipartMemory int64
// UseH2C enable h2c support.
UseH2C bool
// ContextWithFallback enable fallback Context.Deadline(), Context.Done(), Context.Err() and Context.Value() when Context.Request.Context() is not nil.
ContextWithFallback bool
delims render.Delims
secureJSONPrefix string
HTMLRender render.HTMLRender
FuncMap template.FuncMap
allNoRoute HandlersChain
allNoMethod HandlersChain
noRoute HandlersChain
noMethod HandlersChain
pool sync.Pool
trees methodTrees
maxParams uint16
maxSections uint16
trustedProxies []string
trustedCIDRs []*net.IPNet
}
带有明确注释的字段无一例外都是配置向,他们的英文解释也非常明确,基本上是路径匹配和全局配置等。相关常用的几个默认项 为:
// - RedirectTrailingSlash: true
// - RedirectFixedPath: false
// - HandleMethodNotAllowed: false
// - ForwardedByClientIP: true
// - UseRawPath: false
// - UnescapePathValues: true
2.2. 其他字段
除去一些配置字段外,剩下的都是一些基本字段了,我们分块说明下:
2.2.1. 路由
重要
路由是整个主引擎最核心的组件
RouterGroup // 内嵌路由组,支持分组路由管理
trees methodTrees // 按HTTP方法分类的路由树(Radix Tree)
可以认为整个主引擎就继承自路由组,这样可以直接使用路由相关的组件功能,比如 Get、Post 等等。其中trees 是一个相对复杂的结构,它用的是压缩前缀树,关于这一点,我们会在路由组里详细展开。
跟路由相关的配置,我们也可以简单说下,其实就是简单翻一下英文注释。
RedirectTrailingSlash bool // 自动重定向带/不带斜杠的路径
RedirectFixedPath bool // 自动修正路径(如大小写、多余斜杠)
RemoveExtraSlash bool // 允许参数中包含多余斜杠
顺带一提,这个英文注释写的是真的多,看着很头疼,只能说一句原作者比较严谨吧。
2.2.2. 异常路由处理
HandleMethodNotAllowed bool // 处理Method Not Allowed (405)
allNoRoute HandlersChain // 全局404处理器
allNoMethod HandlersChain // 全局405处理器
noRoute HandlersChain // 分组404处理器
noMethod HandlersChain // 分组405处理器
这几个参数是用来处理一些错误请求,比如不存在,或者没权限等等这种。它的使用也比较简单:
router.NoRoute(func(c *gin.Context) {
c.JSON(404, gin.H{"error": "Page not found"})
})
重要
可以利用这一块的特性,设置中间件记录 404 和 405 的请求情况,监控爬虫。
2.2.3. 模板渲染
delims render.Delims // 模板分隔符
secureJSONPrefix string // JSONP安全前缀,用来跨域的
HTMLRender render.HTMLRender // HTML渲染器
FuncMap template.FuncMap // 模板函数映射
这几个参数都是用来定义 HTML 模板的,通过不同的参数可以让 Gin 支持 HTML、XML 等等,但是:
相关信息
前后端分离已经非常成熟,我们现在几乎用不到 Gin 来渲染页面,了解即可。甚至跨域问题,都不一定需要后端来解决。
2.2.4. 客户端 IP 限制
ForwardedByClientIP bool // 从请求头解析客户端IP
RemoteIPHeaders []string // 用于解析IP的请求头列表
TrustedPlatform string // 信任特定平台的IP头(如Google App Engine)
trustedProxies []string //信任IP地址
可以通过配置 IP 白名单,防止伪造 IP 或者一些特殊的网络攻击。
提示
这里有一个很有意思的,sync.pool。关于它,我们会在 Context 里详细聊一聊。
3. 主引擎是怎么启动的
3.1. 初始化
gin 的初始化主要有两个函数,New()和 Default(),但是实际上用的都是 New():
func New() *Engine {
debugPrintWARNINGNew()
engine := &Engine{
RouterGroup: RouterGroup{
Handlers: nil,
basePath: "/",
root: true,
},
FuncMap: template.FuncMap{},
RedirectTrailingSlash: true,
RedirectFixedPath: false,
HandleMethodNotAllowed: false,
ForwardedByClientIP: true,
RemoteIPHeaders: []string{"X-Forwarded-For", "X-Real-IP"},
TrustedPlatform: defaultPlatform,
UseRawPath: false,
RemoveExtraSlash: false,
UnescapePathValues: true,
MaxMultipartMemory: defaultMultipartMemory,
trees: make(methodTrees, 0, 9),
delims: render.Delims{Left: "{{", Right: "}}"},
secureJSONPrefix: "while(1);",
trustedProxies: []string{"0.0.0.0/0", "::/0"},
trustedCIDRs: defaultTrustedCIDRs,
}
engine.RouterGroup.engine = engine
engine.pool.New = func() any {
return engine.allocateContext(engine.maxParams)
}
return engine
}
func Default() *Engine {
debugPrintWARNINGDefault()
engine := New()
engine.Use(Logger(), Recovery())
return engine
}
提示
default 方法,实际上在原有主引擎的基础上,加上了两个自带的中间件,日志和异常回收,关于这两个中间件,我们也会在中间件里面详细展开。
3.2. 服务启动
3.2.1. 基本方法
gin 可以支持多种服务类型,用的最多是 Run 方法:
func (engine *Engine) Run(addr ...string) (err error) {
defer func() { debugPrintError(err) }()
//判断下受信任的IP
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.")
}
//将IP端口合并
address := resolveAddress(addr)
debugPrint("Listening and serving HTTP on %s\n", address)
//注意,gin底层的http 使用的还是官方包,这个方法的Handler方法,底层其实是ServeHTTP
err = http.ListenAndServe(address, engine.Handler())
return
}
// ServeHTTP conforms to the http.Handler interface.
// 这个方法才是真正接收请求,处理服务的地方
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
c := engine.pool.Get().(*Context)
c.writermem.reset(w)
c.Request = req
c.reset()
engine.handleHTTPRequest(c)
engine.pool.Put(c)
}
3.2.2.其他方法
Gin 还支持一些其他类型的服务,我们可以看下:
// RunTLS attaches the router to a http.Server and starts listening and serving HTTPS (secure) requests.
// It is a shortcut for http.ListenAndServeTLS(addr, certFile, keyFile, router)
// Note: this method will block the calling goroutine indefinitely unless an error happens.
func (engine *Engine) RunTLS(addr, certFile, keyFile string) (err error) {
debugPrint("Listening and serving HTTPS on %s\n", addr)
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.")
}
err = http.ListenAndServeTLS(addr, certFile, keyFile, engine.Handler())
return
}
// RunUnix attaches the router to a http.Server and starts listening and serving HTTP requests
// through the specified unix socket (i.e. a file).
// Note: this method will block the calling goroutine indefinitely unless an error happens.
func (engine *Engine) RunUnix(file string) (err error) {
debugPrint("Listening and serving HTTP on unix:/%s", file)
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://github.com/gin-gonic/gin/blob/master/docs/doc.md#dont-trust-all-proxies for details.")
}
listener, err := net.Listen("unix", file)
if err != nil {
return
}
defer listener.Close()
defer os.Remove(file)
err = http.Serve(listener, engine.Handler())
return
}
// RunFd attaches the router to a http.Server and starts listening and serving HTTP requests
// through the specified file descriptor.
// Note: this method will block the calling goroutine indefinitely unless an error happens.
func (engine *Engine) RunFd(fd int) (err error) {
debugPrint("Listening and serving HTTP on fd@%d", fd)
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://github.com/gin-gonic/gin/blob/master/docs/doc.md#dont-trust-all-proxies for details.")
}
f := os.NewFile(uintptr(fd), fmt.Sprintf("fd@%d", fd))
listener, err := net.FileListener(f)
if err != nil {
return
}
defer listener.Close()
err = engine.RunListener(listener)
return
}
// RunListener attaches the router to a http.Server and starts listening and serving HTTP requests
// through the specified net.Listener
func (engine *Engine) RunListener(listener net.Listener) (err error) {
debugPrint("Listening and serving HTTP on listener what's bind with address@%s", listener.Addr())
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://github.com/gin-gonic/gin/blob/master/docs/doc.md#dont-trust-all-proxies for details.")
}
err = http.Serve(listener, engine.Handler())
return
}
提示
这几个用的都不多,了解即可
4. 服务是如何退出的
最近的框架中已经见不到显式的退出,比如 exit 或者 shotdown 等函数。关于这一部分,可以看这一系列的另一篇文章,Gin 框架是如何优雅退出的。