千家信息网

如何掌握编译模板/自定义结构体绑定/http2/操作Cookie

发表于:2026-11-02 作者:千家信息网编辑
千家信息网最后更新 2026年11月02日,这篇文章主要讲解了"如何掌握编译模板/自定义结构体绑定/http2/操作Cookie",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"如何掌握编译模板/自
千家信息网最后更新 2026年11月02日如何掌握编译模板/自定义结构体绑定/http2/操作Cookie

这篇文章主要讲解了"如何掌握编译模板/自定义结构体绑定/http2/操作Cookie",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"如何掌握编译模板/自定义结构体绑定/http2/操作Cookie"吧!

将模板文件一起编译为一个二进制单文件

使用go-assets, 你可以将模板文件和服务一起编译为一个二进制的单文件, 可以方便快捷的部署该服务. 请参考go资产编译器go-assets-builder

使用方法:

1.下载依赖包 go get github.com/gin-gonic/gin go get github.com/jessevdk/go-assets-builder  2.将html文件夹(包含html代码)生成为go资产文件assets.go go-assets-builder html -o assets.go  3.编译构建,将服务打包为单二进制文件 go build -o assets-in-binary  4.运行服务 ./assets-in-binary

go资产文件go-assets.go参考内容如下:

package main  import (   "time"    "github.com/jessevdk/go-assets" )  var _Assetsbfa8d115ce0617d89507412d5393a462f8e9b003 = "\n\n  

Can you see this? → {{.Bar}}

\n\n" var _Assets3737a75b5254ed1f6d588b40a3449721f9ea86c2 = "\n\n

Hello, {{.Foo}}

\n\n" // Assets returns go-assets FileSystem var Assets = assets.NewFileSystem(map[string][]string{"/": {"html"}, "/html": {"bar.tmpl", "index.tmpl"}}, map[string]*assets.File{ "/": { Path: "/", FileMode: 0x800001ed, Mtime: time.Unix(1524365738, 1524365738517125470), Data: nil, }, "/html": { Path: "/html", FileMode: 0x800001ed, Mtime: time.Unix(1524365491, 1524365491289799093), Data: nil, }, "/html/bar.tmpl": { Path: "/html/bar.tmpl", FileMode: 0x1a4, Mtime: time.Unix(1524365491, 1524365491289611557), Data: []byte(_Assetsbfa8d115ce0617d89507412d5393a462f8e9b003), }, "/html/index.tmpl": { Path: "/html/index.tmpl", FileMode: 0x1a4, Mtime: time.Unix(1524365491, 1524365491289995821), Data: []byte(_Assets3737a75b5254ed1f6d588b40a3449721f9ea86c2), }}, "")

main.go

package main  import (   "github.com/gin-gonic/gin"   "io/ioutil"   "net/http"   "strings"   "html/template"  )  func main() {   r := gin.New()    t, err := loadTemplate() //加载go-assets-builder生成的模板   if err != nil {     panic(err)   }   r.SetHTMLTemplate(t)    r.GET("/", func(c *gin.Context) {     c.HTML(http.StatusOK, "/html/index.tmpl",nil)   })   r.Run(":8080") }  // loadTemplate loads templates embedded by go-assets-builder // 加载go-assets-builder生成的资产文件, 返回模板的地址 func loadTemplate() (*template.Template, error) {   t := template.New("")   for name, file := range Assets.Files {     defer file.Close()     if file.IsDir() || !strings.HasSuffix(name, ".tmpl") {  //跳过目录或没有.tmpl后缀的文件       continue     }     h, err := ioutil.ReadAll(file)     if err != nil {       return nil, err     }     t, err = t.New(name).Parse(string(h))  //新建一个模板, 文件名做为模板名, 文件内容作为模板内容     if err != nil {       return nil, err     }   }   return t, nil }

完整示例请查看该目录

使用自定义的结构绑定请求表单

参考实例代码:

type StructA struct {     FieldA string `form:"field_a"` }  type StructB struct {     NestedStruct StructA     FieldB string `form:"field_b"` }  type StructC struct {     NestedStructPointer *StructA     FieldC string `form:"field_c"` }  type StructD struct {     NestedAnonyStruct struct {         FieldX string `form:"field_x"`     }     FieldD string `form:"field_d"` }  func GetDataB(c *gin.Context) {     var b StructB     c.Bind(&b)     c.JSON(200, gin.H{         "a": b.NestedStruct,         "b": b.FieldB,     }) }  func GetDataC(c *gin.Context) {     var b StructC     c.Bind(&b)     c.JSON(200, gin.H{         "a": b.NestedStructPointer,         "c": b.FieldC,     }) }  func GetDataD(c *gin.Context) {     var b StructD     c.Bind(&b)     c.JSON(200, gin.H{         "x": b.NestedAnonyStruct,         "d": b.FieldD,     }) }  func main() {     r := gin.Default()     r.GET("/getb", GetDataB)     r.GET("/getc", GetDataC)     r.GET("/getd", GetDataD)      r.Run() }

使用命令 curl 模拟请求测试和结果如下:

$ curl "http://localhost:8080/getb?field_a=hello&field_b=world" {"a":{"FieldA":"hello"},"b":"world"} $ curl "http://localhost:8080/getc?field_a=hello&field_c=world" {"a":{"FieldA":"hello"},"c":"world"} $ curl "http://localhost:8080/getd?field_x=hello&field_d=world" {"d":"world","x":{"FieldX":"hello"}}

尝试将请求体绑定到不同的结构

常规的方法绑定请求体是调用c.Request.Body, 但是它不能多次被调用

type formA struct {   Foo string `json:"foo" xml:"foo" binding:"required"` }  type formB struct {   Bar string `json:"bar" xml:"bar" binding:"required"` }  func SomeHandler(c *gin.Context) {   objA := formA{}   objB := formB{}   // This c.ShouldBind consumes c.Request.Body and it cannot be reused.   // 使用c.ShoudBind消费c.Request.Body, 但是它只能调用一次   if errA := c.ShouldBind(&objA); errA == nil {     c.String(http.StatusOK, `the body should be formA`)   // Always an error is occurred by this because c.Request.Body is EOF now.   //这里会报错,因为c.Request.Body已经被消费, 会返回文件结束符EOF   } else if errB := c.ShouldBind(&objB); errB == nil {     c.String(http.StatusOK, `the body should be formB`)   } else {     ...   } }

为了解决这个问题, 可以使用c.ShouldBindBodyWith方法.

func SomeHandler(c *gin.Context) {   objA := formA{}   objB := formB{}   // This reads c.Request.Body and stores the result into the context.   // c.ShouldBindBodyWith方法读取c.Request.Body,并且将结果存储到上下文   if errA := c.ShouldBindBodyWith(&objA, binding.JSON); errA == nil {     c.String(http.StatusOK, `the body should be formA`)   // At this time, it reuses body stored in the context.   //再次调用c.ShouldBindBodyWith时, 可以从上下文中复用请求体内容   } else if errB := c.ShouldBindBodyWith(&objB, binding.JSON); errB == nil {     c.String(http.StatusOK, `the body should be formB JSON`)   // And it can accepts other formats 也可以接受其他类型的绑定,比如XML   } else if errB2 := c.ShouldBindBodyWith(&objB, binding.XML); errB2 == nil {     c.String(http.StatusOK, `the body should be formB XML`)   } else {     ...   } }
  • c.ShouldBindBodyWith 该方法在绑定前, 将请求体存储到gin上下文中, 所以这会对性能有轻微的影响, 所以如果你只打算绑定一次的时候, 不应该使用该方法.

  • 这种方式仅仅支持以下格式: JSON, XML, MsgPack,ProtoBuf. 对于其他格式, Query, Form, FormPost, FormMultipart, 可以重复使用c.ShouldBind()方法, 而不会带来类似的性能影响, 详见(#1341)

http2服务推送

为了解决HTTP/1.X的网络资源利用率不够高, 延迟问题等, HTTP/2 引入了服务器推送机制来解决这些问题.

http.Pusher需要go1.8+版本支持. 详见golang博客.

package main  import (   "html/template"   "log"    "github.com/gin-gonic/gin" )  //定义html模板 var html = template.Must(template.New("https").Parse(`     Https Test        

Welcome, Ginner!

`)) func main() { r := gin.Default() r.Static("/assets", "./assets") r.SetHTMLTemplate(html) r.GET("/", func(c *gin.Context) { if pusher := c.Writer.Pusher(); pusher != nil { //获取推送器 // use pusher.Push() to do server push // 使用pusher.Push()方法执行服务端推送动作, 尝试推送app.js文件 if err := pusher.Push("/assets/app.js", nil); err != nil { log.Printf("Failed to push: %v", err) } } c.HTML(200, "https", gin.H{ "status": "success", }) }) // Listen and Server in https://127.0.0.1:8080 r.RunTLS(":8080", "./testdata/server.pem", "./testdata/server.key") }

定义路由日志格式

默认路由日志如下:

[GIN-debug] POST   /foo                      --> main.main.func1 (3 handlers) [GIN-debug] GET    /bar                      --> main.main.func2 (3 handlers) [GIN-debug] GET    /status                   --> main.main.func3 (3 handlers)

如果你想用给定的格式(如:JSON,键值对等)记录路由日志, 你可以使用gin.DebugPrintRouteFunc方法自定义日志格式, 下面的示例, 我们用日志log标准库记录路由器日志, 当然你也可以使用其他适合业务的日志工具.

package main  import (   "log"   "net/http"    "github.com/gin-gonic/gin" )  func main() {   r := gin.Default()   //使用DebugPrintRouteFunc设置路由日志记录格式, 这里使用标准库log包记录请求方法/请求路径/控制器名/控制器链个数,   gin.DebugPrintRouteFunc = func(httpMethod, absolutePath, handlerName string, nuHandlers int) {     log.Printf("endpoint %v %v %v %v\n", httpMethod, absolutePath, handlerName, nuHandlers)   }    r.POST("/foo", func(c *gin.Context) {     c.JSON(http.StatusOK, "foo")   })    r.GET("/bar", func(c *gin.Context) {     c.JSON(http.StatusOK, "bar")   })    r.GET("/status", func(c *gin.Context) {     c.JSON(http.StatusOK, "ok")   })    // Listen and Server in http://0.0.0.0:8080   r.Run() }

设置和读取Cookie

import (     "fmt"      "github.com/gin-gonic/gin" )  func main() {      router := gin.Default()      router.GET("/cookie", func(c *gin.Context) {         //读取Cookie         cookie, err := c.Cookie("gin_cookie")          if err != nil {             cookie = "NotSet"             //设置Cookie             c.SetCookie("gin_cookie", "test", 3600, "/", "localhost", false, true)         }          fmt.Printf("Cookie value: %s \n", cookie)     })      router.Run() }

测试

推荐使用net/http/httptest 包做HTTP测试.

package main  func setupRouter() *gin.Engine {   r := gin.Default()   r.GET("/ping", func(c *gin.Context) {     c.String(200, "pong")   })   return r }  func main() {   r := setupRouter()   r.Run(":8080") }

测试代码示例:

package main  import (   "net/http"   "net/http/httptest"   "testing"    "github.com/stretchr/testify/assert" )  func TestPingRoute(t *testing.T) {   router := setupRouter()    w := httptest.NewRecorder()   req, _ := http.NewRequest("GET", "/ping", nil)   router.ServeHTTP(w, req)   //断言   assert.Equal(t, 200, w.Code)   assert.Equal(t, "pong", w.Body.String()) }

Gin框架用户

其他优质的项目也使用GinWeb框架.

  • gorush: 一个用GO实现的推送通知系统

  • fnproject: 原生容器化, 无服务的跨云平台

  • photoprism: 使用Go和Google的TensorFlow框架支持的个人照片管理

  • krakend: 带有中间件的极致高性能API网关

  • picfit: 使用Go实现的一款图片编辑服务器

  • brigade: 为Kubernetes服务的基于事件驱动的脚本

  • dkron: 分布式, 可靠的任务调度系统

感谢各位的阅读,以上就是"如何掌握编译模板/自定义结构体绑定/http2/操作Cookie"的内容了,经过本文的学习后,相信大家对如何掌握编译模板/自定义结构体绑定/http2/操作Cookie这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是,小编将为大家推送更多相关知识点的文章,欢迎关注!

文件 模板 方法 服务 日志 推送 结构 编译 内容 格式 路由 资产 问题 测试 上下 上下文 二进制 代码 框架 示例 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 上海喔噻互联网科技有限公司 上海睿民互联网科技有限公司 互联网是第几次科技革命的成果 深圳恒合互联网络科技有限公司 A股互联网金融科技公司 广州互联网科技公司 金融科技与互联网金融 智网互联网科技 科技创新互联网企业 融贸通互联网科技 成都狮子座互联网科技 互联网科技公司做什么 和信科技工业互联网 科技类公司包括互联网吗 乌鲁木齐新华智原互联网科技学校 小米互联网科技园入驻 广州燕处互联网科技有限公司 神州科技互联网有限公司 上海互联网科技园景观 科技互联网企业在行动 苏州找大状互联网科技有限公司 互联网络科技有限公司 致骋互联网科技 无线互联网科技 苏州大垚互联网科技 团飞科技与伯堂互联网服务平台 互联网5g黑科技有哪些 2021互联网科技公司排名 互联网科技快讯热点 银川新华互联网科技学校是国营吗
0