🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
### 【GoWeb开发实战】Gin框架\_响应 # 响应 既然请求可以使用不同的content-type,响应也如此。通常响应会有html,text,plain,json和xml等。 gin提供了很优雅的渲染方法。 ## 一、JSON/XML/YAML渲染 创建一个go文件(demo10\_rendering.go): ~~~go package main import ( "github.com/gin-gonic/gin" "net/http" "github.com/gin-gonic/gin/testdata/protoexample" ) func main() { r := gin.Default() // gin.H is a shortcut for map[string]interface{} r.GET("/someJSON", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK}) }) r.GET("/moreJSON", func(c *gin.Context) { // You also can use a struct var msg struct { Name string `json:"user"` Message string Number int } msg.Name = "hanru" msg.Message = "hey" msg.Number = 123 // 注意 msg.Name 变成了 "user" 字段 // 以下方式都会输出 : {"user": "hanru", "Message": "hey", "Number": 123} c.JSON(http.StatusOK, msg) }) r.GET("/someXML", func(c *gin.Context) { c.XML(http.StatusOK, gin.H{"user":"hanru","message": "hey", "status": http.StatusOK}) }) r.GET("/someYAML", func(c *gin.Context) { c.YAML(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK}) }) r.GET("/someProtoBuf", func(c *gin.Context) { reps := []int64{int64(1), int64(2)} label := "test" // The specific definition of protobuf is written in the testdata/protoexample file. data := &protoexample.Test{ Label: &label, Reps: reps, } // Note that data becomes binary data in the response // Will output protoexample.Test protobuf serialized data c.ProtoBuf(http.StatusOK, data) }) // Listen and serve on 0.0.0.0:8080 r.Run(":8080") } ~~~ 运行项目,打开浏览器输入网址:[http://127.0.0.1:8080/moreJSON](http://127.0.0.1:8080/moreJSON) ![gin_yunxing25](http://image.chaindesk.cn/gin_yunxing25.png/mark) 重新输入网址:[http://127.0.0.1:8080/someXML](http://127.0.0.1:8080/someXML) ![gin_yunxing26](http://image.chaindesk.cn/gin_yunxing26.png/mark) ## 二、HTML模板渲染 gin支持加载HTML模板, 然后根据模板参数进行配置并返回相应的数据。 先要使用 LoadHTMLGlob() 或者 LoadHTMLFiles()方法来加载模板文件,新建一个go文件(demo11\_html.go): ~~~go func main() { router := gin.Default() //加载模板 router.LoadHTMLGlob("templates/*") //router.LoadHTMLFiles("templates/template1.html", "templates/template2.html") //定义路由 router.GET("/index", func(c *gin.Context) { //根据完整文件名渲染模板,并传递参数 c.HTML(http.StatusOK, "index.tmpl", gin.H{ "title": "Main website", }) }) router.Run(":8080") } ~~~ 创建一个目录:templates,然后在该目录下创建一个模板文件: templates/index.tmpl ~~~html <html> <h1> {{ .title }} </h1> </html> ~~~ 运行项目,打开浏览器输入地址:[http://127.0.0.1:8080/index](http://127.0.0.1:8080/index) ![gin_yunxing24](http://image.chaindesk.cn/gin_yunxing24.png/mark) 不同文件夹下模板名字可以相同,此时需要 LoadHTMLGlob() 加载两层模板路径。 ~~~go router.LoadHTMLGlob("templates/**/*") router.GET("/posts/index", func(c *gin.Context) { c.HTML(http.StatusOK, "posts/index.tmpl", gin.H{ "title": "Posts", }) c.HTML(http.StatusOK, "users/index.tmpl", gin.H{ "title": "Users", }) }) ~~~ 重启项目后,打开浏览器输入以下网址:[http://127.0.0.1:8080/posts/index](http://127.0.0.1:8080/posts/index) ![gin_yunxing27](http://image.chaindesk.cn/gin_yunxing27.png/mark) gin也可以使用自定义的模板引擎,如下 ~~~go import "html/template" func main() { router := gin.Default() html := template.Must(template.ParseFiles("file1", "file2")) router.SetHTMLTemplate(html) router.Run(":8080") } ~~~ ## 三、文件响应 **静态文件服务** 可以向客户端展示本地的一些文件信息,例如显示某路径下地文件。服务端代码是: ~~~go package main import ( "github.com/gin-gonic/gin" "net/http" ) func main() { router := gin.Default() // 下面测试静态文件服务 // 显示当前文件夹下的所有文件/或者指定文件 router.StaticFS("/showDir", http.Dir(".")) router.StaticFS("/files", http.Dir("/bin")) //Static提供给定文件系统根目录中的文件。 //router.Static("/files", "/bin") router.StaticFile("/image", "./assets/miao.jpg") router.Run(":8080") } ~~~ 打开浏览器,输入地址:[http://127.0.0.1:8080/showDir,访问当前项目目录的内容](http://127.0.0.1:8080/showDir%EF%BC%8C%E8%AE%BF%E9%97%AE%E5%BD%93%E5%89%8D%E9%A1%B9%E7%9B%AE%E7%9B%AE%E5%BD%95%E7%9A%84%E5%86%85%E5%AE%B9) ![gin_yunxing29](http://image.chaindesk.cn/gin_yunxing29.png/mark) 重新输入地址:[http://127.0.0.1:8080/files,访问操作系统/bin的下的内容](http://127.0.0.1:8080/files%EF%BC%8C%E8%AE%BF%E9%97%AE%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/bin%E7%9A%84%E4%B8%8B%E7%9A%84%E5%86%85%E5%AE%B9): ![gin_yunxing30](http://image.chaindesk.cn/gin_yunxing30.png/mark) 浏览器中重新输入地址:[http://127.0.0.1:8080/image](http://127.0.0.1:8080/image) ![gin_yunxing31](http://image.chaindesk.cn/gin_yunxing31.png/mark) ## 四、重定向 新建一个go文件(demo13\_redirect.go): ~~~go package main import ( "github.com/gin-gonic/gin" "net/http" ) func main() { r := gin.Default() r.GET("/redirect", func(c *gin.Context) { //支持内部和外部的重定向 c.Redirect(http.StatusMovedPermanently, "http://www.baidu.com/") }) r.Run(":8080") } ~~~ 打开浏览器输入:[http://127.0.0.1:8080/redirect,我们可以看到通过访问的路径,可以重定向到百度地址](http://127.0.0.1:8080/redirect%EF%BC%8C%E6%88%91%E4%BB%AC%E5%8F%AF%E4%BB%A5%E7%9C%8B%E5%88%B0%E9%80%9A%E8%BF%87%E8%AE%BF%E9%97%AE%E7%9A%84%E8%B7%AF%E5%BE%84%EF%BC%8C%E5%8F%AF%E4%BB%A5%E9%87%8D%E5%AE%9A%E5%90%91%E5%88%B0%E7%99%BE%E5%BA%A6%E5%9C%B0%E5%9D%80)。 ![gin_yunxing28](http://image.chaindesk.cn/gin_yunxing28.png/mark) ## 五、同步异步 goroutine 机制可以方便地实现异步处理。当在中间件或处理程序中启动新的Goroutines时,你不应该在原始上下文使用它,你必须使用只读的副本。 新建一个go文件: ~~~go package main import ( "time" "github.com/gin-gonic/gin" "log" ) func main() { r := gin.Default() //1. 异步 r.GET("/long_async", func(c *gin.Context) { // goroutine 中只能使用只读的上下文 c.Copy() cCp := c.Copy() go func() { time.Sleep(5 * time.Second) // 注意使用只读上下文 log.Println("Done! in path " + cCp.Request.URL.Path) }() }) //2. 同步 r.GET("/long_sync", func(c *gin.Context) { time.Sleep(5 * time.Second) // 注意可以使用原始上下文 log.Println("Done! in path " + c.Request.URL.Path) }) // Listen and serve on 0.0.0.0:8080 r.Run(":8080") } ~~~ 启动程序,打开浏览器并输入网址:[http://127.0.0.1:8080/long\_sync](http://127.0.0.1:8080/long_sync), ![gin_yunxing33](http://image.chaindesk.cn/gin_yunxing33.png/mark) 然后在控制台观察打印的结果: ![gin_yunxing32](http://image.chaindesk.cn/gin_yunxing32.png/mark) 然后我们在浏览器中更改地址:[http://127.0.0.1:8080/long\_async](http://127.0.0.1:8080/long_async), ![gin_yunxing34](http://image.chaindesk.cn/gin_yunxing34.png/mark) 然后观察控制台中打印的内容: ![gin_yunxing35](http://image.chaindesk.cn/gin_yunxing35.png/mark)