当前位置: 首页 > news >正文

网站建设 维护洛阳400电话洛阳网站seo

网站建设 维护,洛阳400电话洛阳网站seo,包装材料营销型网站,网站设计业务Go 源码之 gin 框架 go源码之gin - Jxy 博客 一、总结 gin.New()初始化一个实例#xff1a;gin.engine#xff0c;该实例实现了http.Handler接口。实现了ServeHTTP方法 注册路由、注册中间件#xff0c;调用addRoute将路由和中间件注册到 methodTree 前缀树#xff08;节…Go 源码之 gin 框架 go源码之gin - Jxy 博客 一、总结 gin.New()初始化一个实例gin.engine该实例实现了http.Handler接口。实现了ServeHTTP方法 注册路由、注册中间件调用addRoute将路由和中间件注册到 methodTree 前缀树节省空间搜索快下methodTree 的非叶子节点是相同 method 的 url 的最长公共前缀字符串叶子节点是完整的 url 路径 http请求会执行ServeHTTP方法内部会根据请求的 method 和 url 到前缀树 methodTree 中匹配 url然后遍历 handlers 数组依次执行c.next()执行可以通过c.Abort()进行中断 流程 启动 初始化engine初始化一个长度为 9 的 methodTrees 数组调用 addRoute 注册全局中间件、路由到 methodTree 数组中 处理 gin.engine 实现了 http.handler 接口实现了 ServeHTTP(ResponseWriter, *Request)所有的请求都会经过 ServeHTTP 处理 ServeHTTP 方法从 methodTrees 中找到本次请求的 httpMethod 的 Tree–根据请求Url Path 找到Tree下对应的节点nodeValue包含了中间件handler— 执行c.Next() 依次执行handlerhandler内部 可以调用c.JSON等往响应的http写入数据 注意点 路由中间件的执行顺序和添加顺序一致遵循先进先出规则c.JSON()等是http请求的末端函数如果要添加后置拦截器需要在此之前执行c.Next()即可, c.Abort()为终止执行后续的中间件 使用 sync.Pool 来复用上下午对象 gin 底层依旧是依赖 net/http 包本质上是一个路由处理器实现了 http.handler 接口实现了 ServeHTTP 维护了 method 数组每个元素是一个 radix 树压缩前缀树 gin 的中间件是使用切片实现的添加中间件也就是切片追加元素的过程中间件按追加先后顺序依次执行 gin 允许为不同的路由组添加不同的中间件 路由组本质上是一个模版维护了路径前缀、中间件等信息让用户省去重复配置相同前缀和中间件的操作 新路由组继承父路由组的所有处理器 如果上下文需要并发处理使用需要使用上下文副本copy 二、源码 一engine结构 // Engine的实例包括了路由组路由树中间件和其他等一系列配置 type Engine struct {// 路由组RouterGroup// 如果当前路径无法匹配但存在带有不带有尾斜杠的路径处理程序RedirectTrailingFlash将启用自动重定向// 例如如果请求了/foo/但只有/foo的路由存在则客户端将被重定向到/foo// GET请求的http状态代码为301所有其他请求方法的http状态为307。RedirectTrailingSlash bool// RedirectFixedPath如果启用如果没有为其注册句柄则路由器将尝试 修复 当前请求路径。// 首先删除像../或//这样的多余路径元素。然后路由器对清理后的路径进行不区分大小写的查找。如果可以找到该路由的句柄则路由器对GET请求使用状态代码301// 对所有其他请求方法使用状态代码307重新定向到正确的路径。例如/FOO和/..//FOO可以重定向到/FOO。// RedirectTrailingFlash独立于此选项。RedirectFixedPath bool// HandleMethodNotAllowed如果启用则如果当前请求无法路由则路由器会检查当前路由是否允许其他方法。// 如果是这种情况则使用“Method Not Allowed”和 HTTP状态代码405 回答请求。// 如果不允许其他方法则将请求委托给NotFound处理程序。HandleMethodNotAllowed bool// ForwardedByClientIP如果启用将从与存储在“*gin.Engine.RemoteIPHeaders”中的标头匹配的请求标头解析客户端IP。// 如果未提取任何IP它将返回到从“*gin.Context.Request.Remoddr”获取的IP。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如果启用url.RawPath将用于查找参数。UseRawPath bool// UnescapePathValues如果为true则路径值将被取消转义。// 如果UseRawPath为false默认情况下则UnescapePathValues实际上为true// 作为url。将使用路径该路径已未被覆盖。UnescapePathValues bool// RemoveExtraSlash a parameter can be parsed from the URL even with extra slashes.// See the PR #1817 and issue #1644RemoveExtraSlash 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 IPTrustedPlatform string// MaxMultipartMemory value of maxMemory param that is given to http.Requests 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 booldelims render.Delims// https://cloud.tencent.com/developer/article/1580456secureJSONPrefix string HTMLRender render.HTMLRender// FuncMap是定义从名称到函数的映射的映射类型。// 每个函数必须有一个返回值或两个返回值其中第二个返回值具有类型错误。// 在这种情况下如果在执行期间第二个error参数的计算结果为非nil则执行终止Execute返回该错误。// FuncMap在“text/template”中具有与FuncMap相同的基本类型复制到此处因此客户端无需导入“text/template”。FuncMap template.FuncMap trees methodTrees // 请求的method数组每个元素是一个前缀树}二ServeHTTP核心处理http方法 // 所有的http请求最终都会走这里 func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {c : engine.pool.Get().(*Context) // 从池里取一个contextc.writermem.reset(w) // 重置c.Request req // 赋值请求c.reset() // 重置数据engine.handleHTTPRequest(c) // 核心处理函数engine.pool.Put(c) // 放回缓冲池 } // 核心处理函数 func (engine *Engine) handleHTTPRequest(c *Context) {// 请求的Method类型如GET等httpMethod : c.Request.Method// 请求的路径rPath : c.Request.URL.Pathunescape : falseif engine.UseRawPath len(c.Request.URL.RawPath) 0 {rPath c.Request.URL.RawPathunescape engine.UnescapePathValues}if engine.RemoveExtraSlash {rPath cleanPath(rPath)}// 从methodTree中匹配method和请求urlt : engine.treesfor i, tl : 0, len(t); i tl; i {if t[i].method ! httpMethod {continue}root : t[i].root// 从前缀树methodTree中匹配到叶子节点valuevalue : root.getValue(rPath, c.params, c.skippedNodes, unescape)if value.params ! nil {c.Params *value.params}// 执行中间件if value.handlers ! nil {c.handlers value.handlersc.fullPath value.fullPathc.Next() // 依次从handlers数组中FIFO执行中间件c.writermem.WriteHeaderNow() // 最终写入http响应流responseWriter中return}if httpMethod ! http.MethodConnect rPath ! / {if value.tsr engine.RedirectTrailingSlash {redirectTrailingSlash(c)return}if engine.RedirectFixedPath redirectFixedPath(c, root, engine.RedirectFixedPath) {return}}break}if engine.HandleMethodNotAllowed {for _, tree : range engine.trees {if tree.method httpMethod {continue}if value : tree.root.getValue(rPath, nil, c.skippedNodes, unescape); value.handlers ! nil {c.handlers engine.allNoMethodserveError(c, http.StatusMethodNotAllowed, default405Body)return}}}c.handlers engine.allNoRouteserveError(c, http.StatusNotFound, default404Body) } 三methodTrees 在New() 中会初始化容量为9匹配9个http.Method 每个节点都是压缩前缀树将相同请求method的url计算出最长公共前缀字符串然后作为子节点 type methodTrees []methodTree// 压缩前缀树存储了http.Method的请求路径 type methodTree struct {method stringroot *node } type node struct {path string // 存储共同的最长前缀字符indices stringwildChild boolnType nodeTypepriority uint32children []*node // 有共同的最长前缀字符path的url pathhandlers HandlersChainfullPath string // 叶子节点存储的是完整的请求路径 } // 构建树的函数 func addRoute(){}r : gin.Default()r.Use(gin.Recovery(), gin.Logger())r.GET(/user/GetUserInfo, func(context *gin.Context) {})r.GET(/user/GetManyUserInfo, func(context *gin.Context) {})r.Run(:9091)四context结构 // gin.Context是gin框架中最重要的一部分 type Context struct {writermem responseWriter // 响应的数据流Request *http.Request // 请求句柄Writer ResponseWriter // 响应的Writerhandlers HandlersChain // 中间件handler数组index int8 // handler数组的下标表示已经执行的下标fullPath string // 完整的url路径engine *Engine }五RouterGroup // RouterGroup is used internally to configure router, a RouterGroup is associated with // a prefix and an array of handlers (middleware). // RouterGroup在内部用于配置路由器RouterGroup与前缀和处理程序中间件数组相关联。 type RouterGroup struct {Handlers HandlersChain // 中间件handlerbasePath string // 基础路径engine *Engine root bool // 是否是根节点 }六c.GET() // 调用了handlerhttpMethodhttp.MethodGet其他什么c.POST等都是差不多 func (group *RouterGroup) GET(relativePath string, handlers ...HandlerFunc) IRoutes {return group.handle(http.MethodGet, relativePath, handlers) } func (group *RouterGroup) handle(httpMethod, relativePath string, handlers HandlersChain) IRoutes {// 计算出绝对路径absolutePath : group.calculateAbsolutePath(relativePath)// 将请求的handler和group的全局handler合并handlers group.combineHandlers(handlers)// 添加路由到前缀树methodTree中group.engine.addRoute(httpMethod, absolutePath, handlers)return group.returnObj() } // 根据请求的method和path构建前缀树methodTree func (engine *Engine) addRoute(method, path string, handlers HandlersChain) {assert1(path[0] /, path must begin with /)assert1(method ! , HTTP method can not be empty)assert1(len(handlers) 0, there must be at least one handler)debugPrintRoute(method, path, handlers)// 从数组methodTrees中获取对应method的根节点root : engine.trees.get(method)if root nil {// 不存在常见根节点root new(node)root.fullPath /engine.trees append(engine.trees, methodTree{method: method, root: root})}// 构建前缀树root.addRoute(path, handlers)// Update maxParamsif paramsCount : countParams(path); paramsCount engine.maxParams {engine.maxParams paramsCount}if sectionsCount : countSections(path); sectionsCount engine.maxSections {engine.maxSections sectionsCount} } 七c.JSON func (c *Context) JSON(code int, obj any) {c.Render(code, render.JSON{Data: obj}) } // 将数据写入c.Writer但是还没有响应http func (c *Context) Render(code int, r render.Render) {c.Status(code)if !bodyAllowedForStatus(code) {r.WriteContentType(c.Writer)c.Writer.WriteHeaderNow()return}if err : r.Render(c.Writer); err ! nil {panic(err)} }八c.Next() 非常巧妙的设计这个设计可以用来暂停执行当前handler先执行后面的handler然后再执行当前handler后面的代码 // handlers是一个中间件执行函数的数组[]HandlerFunc func (c *Context) Next() {// index记录 已经执行到数组[]HandlerFunc的下标// index 继续执行后面的handlerFuncc.index for c.index int8(len(c.handlers)) {c.handlers[c.index](c)c.index} }九c.Abort() 可以用来终止后面所有handler的执行 // 这里将 c.index的值改了超级大在c.Next()中会判断c.indexlen(handler)从而达到终止handler执行的效果 func (c *Context) IsAborted() bool {return c.index abortIndex }三、常见问题 如何设置前置拦截器和后置拦截器 方法一 利用 handler 的存储结构所有的 handler 会按顺序添加到数数组 []HandlerFunc 中执行的是按FIFO遍历执行所有先添加的handler会先执行也就是说越先添加的就是前置拦截器越晚添加的就是后置拦截器 r : gin.Default()r.Use(gin.Recovery()) // 前置拦截器r.GET(/user/GetUserInfo, func(context *gin.Context) {}) // 中间执行函数r.Use(func(context *gin.Context) {}) // 后置拦截器方法二 使用c.Next()方法在handler函数内部可以先执行一部分代码然后执行c.Next()会遍历执行后续的handler当所有的handler结束后在执行当前handler c.Next()之后的代码 r : gin.Default()r.Use(, func(c *gin.Context) {// 前置代码c.Next() // 执行所有handler// 后置代码}) r.GET(/user/GetUserInfo, func(context *gin.Context) {}) // 中间执行函数 有劳各位看官 点赞、关注➕收藏 你们的支持是我最大的动力 接下来会不断更新 golang 的一些底层源码及个人开发经验个人见解 同时也欢迎大家在评论区提问、分享您的经验和见解
http://www.pierceye.com/news/102869/

相关文章:

  • 成都市金牛区建设和交通局网站营销专业网站
  • 免费的视频网站如何赚钱wordpress推广系统
  • 上海酒店团购网站建设网站建设风险分析
  • 做网站的抬头怎么做南昌app定制
  • 深圳市企业网站建设企业品牌设计
  • 做图网站有哪些内容惠州抖音推广
  • 郑州中原区建设局网站公司网站建设素材
  • 企业手机网站源码下载企查查网页版
  • 金科网站建设ps做网站难吗
  • 如何在年报网站上做遗失公告wordpress默认摘要
  • 中国网站服务器哪个好有哪些做公司网站
  • 做宠物的网站有哪些如何做电商生意
  • 具有品牌的常州做网站关于网站建设的广告词
  • 孝感网站推广品牌策划公司都有哪些
  • 保洁公司用哪些网站做推广wordpress aj提交评论
  • 互联网金融p2p网站建设模板简历模板免费下载网站
  • 绍兴建设网站制作3免费做网站
  • 东莞运营推广网站建设费用wordpress 单栏 主题
  • 律师事务所网站制作WordPress 经典博客
  • 建立网站功能wordpress微博头条
  • 多就能自己做网站取名网站怎么做
  • 网站域名百度云网站环境建设国家城乡建设规划部网站
  • 网站设计的实例wordpress 微博备份
  • 网络推销黑河网站seo
  • 天津市建设工程管理总队网站wordpress 自媒体模版
  • 用网站做宣传的方案郴州买房网站
  • 微信网站前景wordpress 主题开发教程
  • 基于php旅游网站的毕业设计太原网站建设主页
  • 硅谷网站开发薪酬网站建设 数据可视化
  • 绍兴网站建设设计制作高端的网站开发公司