Go Gin demo
项目目录
demo ─ router ─ router.go
├ handlers ─ hello.go
└ main.go
hello.go
package handlers
import (
"github.com/gin-gonic/gin"
"net/http"
)
func HelloPage(context *gin.Context) {
context.JSON(http.StatusOK, gin.H{
"message": "welcome",
})
}
router.go
package router
import (
"github.com/gin-gonic/gin"
"../handlers"
)
func Init() {
//创建一个默认 gin 路由器
r := gin.Default()//分组路由
//组:v1
v1 := r.Group("/v1")
{
v1.GET("/hello", handlers.HelloPage)
}
r.Run(":8000")// 监听和服务在 0.0.0.0:8000
}
main.go
package main
import "./router"
func main() {
router.Init()
}
测试
执行 main.go 文件后,在浏览器上面输入地址:
http://127.0.0.1:8000/v1/hello
即可以看到浏览器显示:
{"message":"welcome"}
Gin 参数使用
接收url参数
在之前的组v1路由下新定义一个路由:
v1 := r.Group("/v1")
{
v1.GET("/hello", handlers.HelloPage)
v1.GET("/hello/:name", func(context *gin.Context) {
name := context.Param("name")
context.String(http.StatusOK, "Hello %s", name)
})
}
重新运行后,在浏览器输入:
http://127.0.0.1:8000/v1/hello/muzico
即可以看到浏览器显示:
Hello muzico
接收url参数,多个参数
v1.GET("/value/:a/:b", func(context *gin.Context) {
value_a := context.Param("a")
value_b := context.Param("b")
context.String(http.StatusOK, "value a:%s b:%s", value_a, value_b)
})
重新运行后,在浏览器输入:
http://127.0.0.1:8000/v1/value/1/2
即可以看到浏览器显示:
value a:1 b:2
但如果地址少了一个参数就会处理失败,返回 "404 page not found" 页面。
除非另外追加相对应的路由进行处理:
v1.GET("/value/:a", func(context *gin.Context) {
value_a := context.Param("a")
context.String(http.StatusOK, "value a:%s", value_a)
})
v1.GET("/value/", func(context *gin.Context) {
context.String(http.StatusOK, "value 没有参数")
})
通过c.Param("key")方法,Gin成功捕获了url请求路径中的参数
这种方式可以获取不定数据的参数。
v1.GET("/welcome", func(context *gin.Context) {
firstname := context.DefaultQuery("firstname", "Guest")
lastname := context.Query("lastname")
context.String(http.StatusOK, "Hello %s %s", firstname, lastname)
})
重新运行后,在浏览器输入:
http://127.0.0.1:8000/v1/welcome
即可以看到浏览器显示:
Hello Guest
该路由的 firstname 值默认为 "Guest"
在浏览器输入:
http://127.0.0.1:8000/v1/welcome?lastname=muzico&firstname=yococo
即可以看到浏览器显示:
Hello yococo muzico
Gin返回静态页面
创建目录文件
demo ─ templates ─ index.html
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body>
<h1>{{ .title }}</h1>
</body>
</html>
创建group v2,并创建 /index 路由,返回精通 html 页面:
r.LoadHTMLGlob(getCurrentPath() + "/demo/templates/*")
v2 := r.Group("/v2")
{
v2.GET("/index", func(context *gin.Context) {
context.HTML(http.StatusOK, "index.html", gin.H{
"title": "hello world!",
})
})
}
获取项目路径
func getCurrentPath() string {
str, _ := os.Getwd()
return str
}
在浏览器输入:
http://127.0.0.1:8000/v2/index
即可以看到,Gin返回了静态文件index.html,并把title数据填充到了模板 {{ .title }}
Gin默认路由
//404 NotFound
r.NoRoute(func(context *gin.Context) {
context.JSON(http.StatusNotFound, gin.H{
"status" : 404,
"error": "404, page not exists!",
})
})
在浏览器输入不存在,或不正确的地址。
即可以看到浏览器显示:
{"error":"404, page not exists!","status":404}
Gin 中间件
在go的net/http中我们可以很方便的设计中间件,同样Gin也为我们提供了很方便的中间件使用。 我们可以定义全局中间件,群组中间件和单个路由的中间件,可以限定中间件的作用范围。
先定义一个简单的中间件,并将其设为全局中间件:
func PrintMiddleware(context *gin.Context) {
fmt.Print("before request")
context.Next()
}
接下来注册为全局中间件:
r := gin.Default()//分组路由
r.Use(PrintMiddleware)
在浏览器输入:
http://127.0.0.1:8000/v2/index
可以看到控制器输出的信息:
[GIN-debug] GET /v2/index --> _/Users/muzico/Documents/Project/go/test03/demo/router.Init.func6 (4 handlers)
[GIN-debug] Listening and serving HTTP on :8000
before request[GIN] 2019/04/12 - 14:38:43 | 200 | 585.483µs | 127.0.0.1 | GET /v2/index
可以看到Gin在执行请求前,成功执行了自定义的中间件函数,c.Next()表示当中间件执行完成之后,将请求传递给下一个函数处理。
现在我们想对v2组的请求进行一次验证(模拟登录),假设请求中包含一个token参数,存储认证信息,我们来实现这个中间件函数:
func ValidateToken() gin.HandlerFunc {
return func(context *gin.Context) {
token := context.Request.FormValue("token")
if token == "" {
context.JSON(401, gin.H{
"message": "Token required",
})
context.Abort()
return
}
if token != "accesstoken" {
context.JSON(http.StatusOK, gin.H{
"message": "Invalid Token",
})
context.Abort()
return
}
context.Next()
}
}
然后我们在group v2组注册这个中间件:
r.Use(ValidateToken())
在浏览器输入:
http://127.0.0.1:8000/v2/index
即可以看到浏览器显示:
{"message":"Token required"}
而在浏览器输入:
http://127.0.0.1:8000/v2/index?token=accesstoken
则可以看到:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body>
<h1>hello world!</h1>
</body>
</html>
可以看到已经通过验证,Gin正确响应了请求。c.Abort()表示请求被终止。
完整的 router.go 代码:
package router
import (
"fmt"
"github.com/gin-gonic/gin"
"../handlers"
"net/http"
"os"
)
func Init() {
//创建一个默认 gin 路由器
r := gin.Default()//分组路由
r.Use(PrintMiddleware)
r.Use(ValidateToken())
//组:v1
v1 := r.Group("/v1")
{
v1.GET("/hello", handlers.HelloPage)
v1.GET("/hello/:name", func(context *gin.Context) {
name := context.Param("name")
context.String(http.StatusOK, "Hello %s", name)
})
v1.GET("/value/:a/:b", func(context *gin.Context) {
value_a := context.Param("a")
value_b := context.Param("b")
context.String(http.StatusOK, "value a:%s b:%s", value_a, value_b)
})
v1.GET("/value/:a", func(context *gin.Context) {
value_a := context.Param("a")
context.String(http.StatusOK, "value a:%s", value_a)
})
v1.GET("/value/", func(context *gin.Context) {
context.String(http.StatusOK, "value 没有参数")
})
v1.GET("/welcome", func(context *gin.Context) {
firstname := context.DefaultQuery("firstname", "Guest")
lastname := context.Query("lastname")
context.String(http.StatusOK, "Hello %s %s", firstname, lastname)
})
}
r.LoadHTMLGlob(getCurrentPath() + "/demo/templates/*")
v2 := r.Group("/v2")
{
v2.GET("/index", func(context *gin.Context) {
context.HTML(http.StatusOK, "index.html", gin.H{
"title": "hello world!",
})
})
}
r.NoRoute(func(context *gin.Context) {
context.JSON(http.StatusNotFound, gin.H{
"status" : 404,
"error": "404, page not exists!",
})
})
r.Run(":8000")// 监听和服务在 0.0.0.0:8000
}
func getCurrentPath() string {
str, _ := os.Getwd()
return str
}
func PrintMiddleware(context *gin.Context) {
fmt.Print("before request")
context.Next()
}
func ValidateToken() gin.HandlerFunc {
return func(context *gin.Context) {
token := context.Request.FormValue("token")
if token == "" {
context.JSON(401, gin.H{
"message": "Token required",
})
context.Abort()
return
}
if token != "accesstoken" {
context.JSON(http.StatusOK, gin.H{
"message": "Invalid Token",
})
context.Abort()
return
}
context.Next()
}
}