Gin Web Framework part 9

Gin Web Framework part 9درود دوستان امروز میخوام در مورد بخش هشتم از سری مقالات فرم ورک Gin صحبت کنیمفهرست بخش هشتم از این مقالهRun multiple service using GinGraceful shutdown or restartBuild a single binary with templatesBind form-data request with custom structTry to bind body into different structshttp2 server pushDefine format for the log of routesSet and get a cookieTestingمیریم واسه توضیح هر بخشقسمت اول Run multiple service using Ginاگه چندتا سرویس داشته باشید به صورت زیر باید عمل کند. توضیحات در ادامه این کدpackage main import ( &quotlog&quot &quotnet/http&quot &quottime&quot &quotgithub.com/gin-gonic/gin&quot &quotgolang.org/x/sync/errgroup&quot ) var ( g errgroup.Group ) func r01() http.Handler { e := gin.New() e.Use(gin.Recovery()) e.GET(&quot/&quot, func(c *gin.Context) { c.JSON( http.StatusOK, gin.H{ &quotcode&quot: http.StatusOK, &quoterror&quot: &quotWelcome server 01&quot, }, ) }) return e } func r02() http.Handler { e := gin.New() e.Use(gin.Recovery()) e.GET(&quot/&quot, func(c *gin.Context) { c.JSON( http.StatusOK, gin.H{ &quotcode&quot: http.StatusOK, &quoterror&quot: &quotWelcome server 02&quot, }, ) }) return e } func main() { server01 := &http.Server{ Addr: &quot:8080&quot, Handler: r01(), ReadTimeout: 5 * time.Second, WriteTimeout: 10 * time.Second, } server02 := &http.Server{ Addr: &quot:8081&quot, Handler: r02(), ReadTimeout: 5 * time.Second, WriteTimeout: 10 * time.Second, } g.Go(func() error { err := server01.ListenAndServe() if err != nil && err != http.ErrServerClosed { log.Fatal(err) } return err }) g.Go(func() error { err := server02.ListenAndServe() if err != nil && err != http.ErrServerClosed { log.Fatal(err) } return err }) if err := g.Wait(); err != nil { log.Fatal(err) } }اول از همه برای اجرا کردن چندین سرویس باید از کتابحانه x/sync/errgroup استفاده کرد که توی خط ۱۲ اومدیم یه نمونه ازش ساختیم. بعدش اومدیم دوتا روت تعریف کردیم به اسم های r01 و r02 توی تابع اصلی اومدیم برای هرکدومشون یه پورت جداگانه درنظر گرفتیم و بعدش در همین تابع اصلی با استفاده از کتابخانه ای که در این فایل تعریف کردیم یعنی x/sync/errgroup اومدیم تابعی به این صورت g.Go(func() error تعریف کردیم از نمونه ای که از این کتابخانه توی خط ۱۲ تعریف کرده بودیم توی بتن این تابع اومدیم نوع سرویس های که شخصی کردیم رو بهش پاس میدیم جهت اجرا شدنقسمت دوم Graceful shutdown or restartچگونه سیگنال‌های ورودی سیستم عامل را برای انجام graceful shutdown در یک وب سرور نوشته‌می‌شوند و ما آن‌ها را به زبان Go مدیریت کنیم.واسه توضیحات بیشتر این مقاله ویرگولی رو بخونید.چندتا کتابخونه توی این زمینه هستن که عبارتنداز:manners: A polite Go HTTP server that shuts down gracefully.graceful: Graceful is a Go package enabling graceful shutdown of an http.Handler server.grace: Graceful restart & zero downtime deploy for Go servers.endless: Zero downtime restarts for go servers (Drop in replacement for http.ListenAndServe)قسمت سوم Build a single binary with templatesواسه اینکه بخواید از فایل html خود یه فایل باینری بسازید کافیه مراحل زیر رو به ترتیب برید. برای اطلاعات بیشتر و همچنین یه مثال ساده به این لینک یه سری بزنیدPrepare Packagesgo get github.com/gin-gonic/gin go get github.com/jessevdk/go-assets-builderGenerate assets.gogo-assets-builder html -o assets.goBuild the servergo build -o assets-in-binaryRun./assets-in-binaryقسمت چهارم Bind form-data request with custom structاگه بخواید استراکچر خودتون رو بسازید به صورت زیر می تونید استراکچر شخصی برای اطلاعات بسازید کد زیر دیگه واضح هست انتظار دارم دیگه اینو بلد باشیدtype StructA struct { FieldA string `form:&quotfield_a&quot` } type StructB struct { NestedStruct StructA FieldB string `form:&quotfield_b&quot` } type StructC struct { NestedStructPointer *StructA FieldC string `form:&quotfield_c&quot` } type StructD struct { NestedAnonyStruct struct { FieldX string `form:&quotfield_x&quot` } FieldD string `form:&quotfield_d&quot` } func GetDataB(c *gin.Context) { var b StructB c.Bind(&b) c.JSON(200, gin.H{ &quota&quot: b.NestedStruct, &quotb&quot: b.FieldB, }) } func GetDataC(c *gin.Context) { var b StructC c.Bind(&b) c.JSON(200, gin.H{ &quota&quot: b.NestedStructPointer, &quotc&quot: b.FieldC, }) } func GetDataD(c *gin.Context) { var b StructD c.Bind(&b) c.JSON(200, gin.H{ &quotx&quot: b.NestedAnonyStruct, &quotd&quot: b.FieldD, }) } func main() { r := gin.Default() r.GET(&quot/getb&quot, GetDataB) r.GET(&quot/getc&quot, GetDataC) r.GET(&quot/getd&quot, GetDataD) r.Run() }نحوه اجرا:$ curl &quothttp://localhost:8080/getb?field_a=hello&field_b=world&quot {&quota&quot:{&quotFieldA&quot:&quothello&quot},&quotb&quot:&quotworld&quot} $ curl &quothttp://localhost:8080/getc?field_a=hello&field_c=world&quot {&quota&quot:{&quotFieldA&quot:&quothello&quot},&quotc&quot:&quotworld&quot} $ curl &quothttp://localhost:8080/getd?field_x=hello&field_d=world&quot {&quotd&quot:&quotworld&quot,&quotx&quot:{&quotFieldX&quot:&quothello&quot}}قسمت پنجم Try to bind body into different structsفرض کنید یه استراکچر دارید که تایپ های مختلف برای ارسال رو پوشش میده و میخواید هم از json و هم از xml اون استراکچر استفاده کنید. برای این کار از متد c.ShouldBindBodyWith استفاده می کنیمبه صورت کد زیر:type formA struct { Foo string `json:&quotfoo&quot xml:&quotfoo&quot binding:&quotrequired&quot` } type formB struct { Bar string `json:&quotbar&quot xml:&quotbar&quot binding:&quotrequired&quot` } func SomeHandler(c *gin.Context) { objA := formA{} objB := formB{} if errA := c.ShouldBindBodyWith(&objA, binding.JSON); errA == nil { c.String(http.StatusOK, `the body should be formA`) } else if errB := c.ShouldBindBodyWith(&objB, binding.JSON); errB == nil { c.String(http.StatusOK, `the body should be formB JSON`) } else if errB2 := c.ShouldBindBodyWith(&objB, binding.XML); errB2 == nil { c.String(http.StatusOK, `the body should be formB XML`) } else { // TODO : YOUR CODE } }قسمت شیشم http2 server pushاین روش در واقع طراحی شده http2 هست که در شکل زیر نماینگر این ارتباط از نوع http2 هستhttps://blog.golang.org/h2pushدر شکل این توضبح دیگه خیلی واضح هست پس من توضیح نمیدم میرم سر اصل قضیهاینم نمونه کد:package main import ( &quothtml/template&quot &quotlog&quot &quotgithub.com/gin-gonic/gin&quot ) var html = template.Must(template.New(&quothttps&quot).Parse(` <html> <head> <title>Https Test</title> <script src=&quot/assets/app.js&quot> </head> <body> <h1 style=&quotcolor:red;&quot>Welcome, Ginner!</h1> </body> </html> `)) func main() { r := gin.Default() r.Static(&quot/assets&quot, &quot./assets&quot) r.SetHTMLTemplate(html) r.GET(&quot/&quot, func(c *gin.Context) { if pusher := c.Writer.Pusher(); pusher != nil { if err := pusher.Push(&quot/assets/app.js&quot, nil); err != nil { log.Printf(&quotFailed to push: %v&quot, err) } } c.HTML(200, &quothttps&quot, gin.H{ &quotstatus&quot: &quotsuccess&quot, }) }) r.RunTLS(&quot:8080&quot, &quot./testdata/server.pem&quot, &quot./testdata/server.key&quot) }برای استفاده از چنین قابلیتی از متد c.Writer.Pusher استفاده می کنیم اگه به شکل نگاه کنید می فهمید نخوه ارتباط با اجزای مختلف یه سایت که چگونه اونا رو برای کاربر نمایش میده یعنی با یه req ما می تونیم از سمت سرور چندین res رو داشته باشیم.قسمت هفتم Define format for the log of routesبرای اینکه بتونیم یه لاگ اختصاصی از عملکرد سرویس هامون داشته باشیم یعنی زمانی که اجرا می کنید توی کنسول چنین چیزی داشته باشید[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)باید از متد gin.DebugPrintRouteFunc استفاده کنیم که توی کد زیر نشون دادیمimport ( &quotlog&quot &quotnet/http&quot &quotgithub.com/gin-gonic/gin&quot ) func main() { r := gin.Default() gin.DebugPrintRouteFunc = func(httpMethod, absolutePath, handlerName string, nuHandlers int) { log.Printf(&quotendpoint %v %v %v %v\n&quot, httpMethod, absolutePath, handlerName, nuHandlers) } r.POST(&quot/foo&quot, func(c *gin.Context) { c.JSON(http.StatusOK, &quotfoo&quot) }) r.GET(&quot/bar&quot, func(c *gin.Context) { c.JSON(http.StatusOK, &quotbar&quot) }) r.GET(&quot/status&quot, func(c *gin.Context) { c.JSON(http.StatusOK, &quotok&quot) }) // Listen and Server in http://0.0.0.0:8080 r.Run() }قسمت هشتم Set and get a cookieنحوه ست کردن و دریافت کوگیimport ( &quotfmt&quot &quotgithub.com/gin-gonic/gin&quot ) func main() { router := gin.Default() router.GET(&quot/cookie&quot, func(c *gin.Context) { cookie, err := c.Cookie(&quotgin_cookie&quot) if err != nil { cookie = &quotNotSet&quot c.SetCookie(&quotgin_cookie&quot, &quottest&quot, 3600, &quot/&quot, &quotlocalhost&quot, false, true) } fmt.Printf(&quotCookie value: %s \n&quot, cookie) }) router.Run() }برای ست کردن کوکی در خط ۱۰ ما یه کوکی تعریف کردیم و بهش یه نام اختصاص دادیم توی خط ۱۲ یع مقدار بهش دادیم و توی ۱۳ اومدیم گفتیم که این کوکی رو توی این آدرس و توی این پورت ست کنپایان اموزش فرم ورک gin اگه سوالی داشتید زیر هر پست برامون کامنت کنید