响应
Quote
既然请求可以使用不同的content-type,响应也如此。通常响应会有html,text,plain,json和xml等。 gin提供了很优雅的渲染方法。
JSON/XML/YAML/ProtoBuf 方式渲染
// 也可以使用结构体返回
r.GET("/moreJson", func(context *gin.Context) {
var msg struct {
Name string `json:"user"`
Msg string
Code int
}
msg.Name = "Jartin"
msg.Msg = "结构体返回成功"
msg.Code = 200
// 注意 msg.Name 变成了 "user" 字段
//以下方式都会输出 : {"user": "Jartin", "Msg": "结构体返回成功", "Code": 200}
context.JSON(http.StatusOK, msg)
})
package main
import (
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/testdata/protoexample"
"net/http"
)
func main() {
r := gin.Default()
// H是map[string]接口{}的快捷方式
r.GET("/resJson", func(context *gin.Context) {
context.JSON(http.StatusOK, gin.H{"msg": "response is success", "status": "status is ok"})
})
// 也可以使用结构体返回
r.GET("/moreJson", func(context *gin.Context) {
var msg struct {
Name string `json:"user"`
Msg string
Code int
}
msg.Name = "Jartin"
msg.Msg = "结构体返回成功"
msg.Code = 200
// 注意 msg.Name 变成了 "user" 字段
//以下方式都会输出 : {"user": "Jartin", "Msg": "结构体返回成功", "Code": 200}
context.JSON(http.StatusOK, msg)
})
// 返回xml
r.GET("someXML", func(context *gin.Context) {
context.XML(http.StatusOK, gin.H{"user": "jartin", "status": http.StatusOK})
})
// 返回YAML
r.GET("/someProtoBuf", func(context *gin.Context) {
context.YAML(http.StatusOK, gin.H{"user": "jartin", "code": http.StatusOK})
})
// 返回protoBuf
r.GET("/someProtoBuf", func(context *gin.Context) {
reps := []int64{int64(1), int64(2)}
label := "test"
//protobuf的具体定义写在testdata/protoexample文件中
data := &protoexample.Test{
Label: &label,
Reps: reps,
}
// 请注意,数据在响应中变为二进制数据
// 将输出原型。测试序列化数据的原型
context.ProtoBuf(http.StatusOK, data)
})
r.Run(":80")
}
HTML模板渲染
- gin支持加载HTML模板, 然后根据模板参数进行配置并返回相应的数据
- 先要使用 LoadHTMLGlob() 或者 LoadHTMLFiles()方法来加载模板文件,
LoadHTMLFiles
方法不会脚本注入
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
r := gin.Default()
//加载模版
r.LoadHTMLGlob("templates/*")
//r.LoadHTMLFiles("templates/template1.html", "templates/template2.html")
// 定义路由
r.GET("/index", func(context *gin.Context) {
// 根据完整文件名渲染模版,并传递参数
context.HTML(http.StatusOK, "index.tmpl", gin.H{"title": "弹力笔记"})
})
r.Run(":80")
}
不同文件夹下模板名字可以相同,此时需要 LoadHTMLGlob() 加载两层模板路径。
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
r := gin.Default()
// 加载模版
/**
这个**代表的是所有目录, *代表的是所有文件 ;
假如templates文件夹下面没有posts文件夹与users文件夹,模板文件都是直接放在templates文件夹下,则写成`templates/*` 即可
*/
r.LoadHTMLGlob("templates/**/*")
r.GET("/posts", func(context *gin.Context) {
context.HTML(http.StatusOK, "posts/index.tmpl", gin.H{
"title": "Posts",
})
})
r.GET("/users", func(context *gin.Context) {
context.HTML(http.StatusOK, "users/index.tmpl", gin.H{
"title": "Users",
})
})
r.Run(":80")
}
jartin@macbookpro1 elastic_notes % curl localhost/posts
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>posts/index</title>
</head>
<body>
Posts
</body>
</html>
jartin@macbookpro1 elastic_notes % curl localhost/users
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>users/index</title>
</head>
<body>
Users
</body>
</html>
文件响应
- 静态文件服务
- 可以向客户端展示本地的一些文件信息,例如显示某路径下地文件。服务端代码是:
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
r := gin.Default()
// 下面测试静态文件服务
// 显示当前文件夹下所有文件/或指定文件
r.StaticFS("/showDir", http.Dir("."))
r.StaticFS("/files", http.Dir("/bin"))
// static提供给定文件系统根目录中的文件
// r.Static("/files", "/bin")
r.StaticFile("/image", "./assets/demo.png")
r.Run(":80")
}
http://localhost/showDir/
.DS_Store
.idea/
assets/
bin/
go.mod
...
http://localhost/files/
bash
cat
chmod
cp
csh
dash
...
重定向
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
r := gin.Default()
r.GET("/redirect", func(context *gin.Context) {
// 支持内部和外部重定向
context.Redirect(http.StatusMovedPermanently, "http://www.baidu.com")
})
r.Run(":80")
}
同步异步
- goroutine 机制可以方便地实现异步处理。当在中间件或处理程序中启动新的Goroutines时,你不应该在原始上下文使用它,你必须使用只读的副本。
package main import ( "github.com/gin-gonic/gin" "log" "time" ) func main() { r := gin.Default() // 异步 r.GET("/long_async", func(context *gin.Context) { // goroutine 中只能使用只读上下文 c.Copy() cCp := context.Copy() go func() { time.Sleep(5 * time.Second) // 注意使用只读上下文 log.Println("Done! in path" + cCp.Request.URL.Path) }() }) // 异步 r.GET("/long_sync", func(context *gin.Context) { time.Sleep(5 * time.Second) // 注意可以使用原始上下文 log.Println("Done! in path" + context.Request.URL.Path) }) r.Run(":80") }
jartin@macbookpro1 elastic_notes % curl localhost/long_async [GIN] 2023/10/07 - 18:27:20 | 200 | 25.802µs | ::1 | GET "/long_async" 2023/10/07 18:27:25 Done! in path/long_async jartin@macbookpro1 elastic_notes % curl localhost/long_sync 2023/10/07 18:28:34 Done! in path/long_sync [GIN] 2023/10/07 - 18:28:34 | 200 | 5.001236448s | ::1 | GET "/long_sync"