Gin 是一款用 Go(Golang) 编写的 web 框架
Gin is a web framework written in Go (Golang). It features a martini-like API with much better performance, up to 40 times faster thanks to httprouter
因为 httprouter, 它提供了更高的性能
这里演示一下 Gin 的模型绑定和确认
使用 model binding 来将请求中的数据绑定到一个 model 中,形成一个结构体,Gin 目前支持绑定 JSON XML 和标准的表单数据 (foo=bar&boo=baz)
Gin 使用 go-playground/validator.v8
来对数据进行校验,详细标记可以参考 package validator
gin 的 API 可以参考 API REFFERENCE
Tip: 当前的版本为 Gin 1.2 和 Go 1.10 (但是实验环境下,Go没有使用最新的版本)
[root@h160 ~]# hostnamectl
Static hostname: h160
Icon name: computer-vm
Chassis: vm
Machine ID: d46f9440d4be429ea66b726977adf233
Boot ID: a0fc6a1b4f124e39a27866d4df0701fa
Virtualization: kvm
Operating System: CentOS Linux 7 (Core)
CPE OS Name: cpe:/o:centos:centos:7
Kernel: Linux 3.10.0-862.2.3.el7.x86_64
Architecture: x86-64
[root@h160 ~]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 52:54:00:c9:c7:04 brd ff:ff:ff:ff:ff:ff
inet 10.0.2.15/24 brd 10.0.2.255 scope global noprefixroute dynamic eth0
valid_lft 84363sec preferred_lft 84363sec
inet6 fe80::5054:ff:fec9:c704/64 scope link
valid_lft forever preferred_lft forever
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 08:00:27:48:f4:2c brd ff:ff:ff:ff:ff:ff
inet 192.168.56.160/24 brd 192.168.56.255 scope global noprefixroute eth1
valid_lft forever preferred_lft forever
inet6 fe80::a00:27ff:fe48:f42c/64 scope link
valid_lft forever preferred_lft forever
[root@h160 ~]# go version
go version go1.9.4 linux/amd64
[root@h160 ~]#
[vagrant@h160 ~]$ echo $GOPATH
/vagrant/go
[vagrant@h160 ~]$ cd $GOPATH
[vagrant@h160 go]$ pwd
/vagrant/go
[vagrant@h160 go]$
package main //指明此包为 main 包
import ( //使用这种方式导入多个包可以更为简洁
"io" //io 包可以提供基础的接口以进行I/O类操作
"net/http" //http.StatusOK 需要用到这个包
"os" //os 包可以提供抽象的操作系统函数
"github.com/gin-gonic/gin" //导入 gin 包
)
// 从 JSON 绑定数据
type Login struct { //构建一个为 Login 的结构体
User string `form:"user" json:"user" binding:"required"` // 属性 User 为必要的,取自 json 类型数据,key 为 user
Password string `form:"password" json:"password" binding:"required"` //属性 Password 为必要的,取自 json 类型数据, key 为 pass
}
func main() { // 一个main包中有且只有一个main 函数
gin.DisableConsoleColor() //DisableConsoleColor 在console 中关闭彩色输出.
f, _ := os.Create("gin.log") //func Create(name string) (*File, error) 接受一个文件名字符串,反馈一个文件指针,和一个错误输出
gin.DefaultWriter = io.MultiWriter(f, os.Stdout) //将输出写出到文件与终端各一份
r := gin.Default() // 使用 gin.Default() 方法生成一个引擎实例,这个实例默认情况下已经将 Logger Recovery 进行了装载
r.POST("/loginJSON", func(c *gin.Context) { //POST 是 router.Handle("POST", path, handle)的快捷方式 func (group *RouterGroup) POST(relativePath string, handlers ...HandlerFunc) IRoutes
var json Login //设定一个 Login 类型的结构体 json
if err := c.ShouldBindJSON(&json); err == nil { //判断 ShouldBindJSON 的结果 err 是否为nil,如果为nil 就执行 if 判断语句块,func (c *Context) ShouldBindJSON(obj interface{}) error ShouldBindJSON 是 c.ShouldBindWith(obj, binding.JSON) 的快捷方式
if json.User == "manu" && json.Password == "123" { // 接着判断结构体 json 中 User 和 Password 是否为指定值
c.JSON(http.StatusOK, gin.H{"status": "you are logged in"}) //反馈一个登录成功的 json 信息
} else {
c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"}) //否则反馈一个登录不成功的 json 信息
}
} else {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) //判断 ShouldBindJSON 的结果 err 不为nil,如果不为nil 就执行 else 判断语句块, 将错误提醒打印出来
}
})
r.POST("/loginForm", func(c *gin.Context) { //POST 是 router.Handle("POST", path, handle)的快捷方式 func (group *RouterGroup) POST(relativePath string, handlers ...HandlerFunc) IRoutes
var form Login //设定一个 Login 类型的结构体 form
if err := c.ShouldBind(&form); err == nil { //判断 ShouldBind 的结果 err 是否为nil,如果为nil 就执行 if 判断语句块 func (c *Context) ShouldBind(obj interface{}) error ShouldBind checks the Content-Type to select a binding engine automatically, Depending the "Content-Type" header different bindings are used
if form.User == "manu" && form.Password == "123" { // 接着判断结构体 form 中 User 和 Password 是否为指定值
c.JSON(http.StatusOK, gin.H{"status": "you are logged in"}) //反馈一个登录成功的 json 信息
} else {
c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"}) //否则反馈一个登录不成功的 json 信息
}
} else {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) //判断 ShouldBind 的结果 err 不为nil,如果不为nil 就执行 else 判断语句块, 将错误提醒打印出来
}
})
r.Run(":8080") //在 0.0.0.0:8080 上启监听
}
[vagrant@h160 go]$ go run hello.go
[GIN-debug] [WARNING] Now Gin requires Go 1.6 or later and Go 1.7 will be required soon.
[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.
[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
- using env: export GIN_MODE=release
- using code: gin.SetMode(gin.ReleaseMode)
[GIN-debug] POST /loginJSON --> main.main.func1 (3 handlers)
[GIN-debug] POST /loginForm --> main.main.func2 (3 handlers)
[GIN-debug] Listening and serving HTTP on :8080
[GIN] 2018/07/11 - 16:14:57 | 400 | 1.487198ms | 192.168.56.105 | POST /loginJSON
[GIN] 2018/07/11 - 16:15:12 | 200 | 193.097µs | 192.168.56.105 | POST /loginJSON
[GIN] 2018/07/11 - 16:15:27 | 200 | 181.733µs | 192.168.56.105 | POST /loginForm
[GIN] 2018/07/11 - 16:15:34 | 400 | 368.599µs | 192.168.56.105 | POST /loginForm
[GIN] 2018/07/11 - 16:16:09 | 401 | 134.971µs | 192.168.56.105 | POST /loginForm
[GIN] 2018/07/11 - 16:16:17 | 200 | 140.609µs | 192.168.56.105 | POST /loginForm
[GIN] 2018/07/11 - 16:18:09 | 400 | 225.385µs | 192.168.56.105 | POST /loginForm
...
...
...
客户的请求为
[vagrant@h105 ~]$ curl -v -X POST http://192.168.56.160:8080/loginJSON -H 'content-type: application/json' -d '{ "user": "manu" }'
* About to connect() to 192.168.56.160 port 8080 (#0)
* Trying 192.168.56.160...
* Connected to 192.168.56.160 (192.168.56.160) port 8080 (#0)
> POST /loginJSON HTTP/1.1
> User-Agent: curl/7.29.0
> Host: 192.168.56.160:8080
> Accept: */*
> content-type: application/json
> Content-Length: 18
>
* upload completely sent off: 18 out of 18 bytes
< HTTP/1.1 400 Bad Request
< Content-Type: application/json; charset=utf-8
< Date: Wed, 11 Jul 2018 16:14:57 GMT
< Content-Length: 100
<
* Connection #0 to host 192.168.56.160 left intact
{"error":"Key: 'Login.Password' Error:Field validation for 'Password' failed on the 'required' tag"}[vagrant@h105 ~]$
[vagrant@h105 ~]$
[vagrant@h105 ~]$
[vagrant@h105 ~]$ curl -v -X POST http://192.168.56.160:8080/loginJSON -H 'content-type: application/json' -d '{ "user": "manu" ,"password":"123"}'
* About to connect() to 192.168.56.160 port 8080 (#0)
* Trying 192.168.56.160...
* Connected to 192.168.56.160 (192.168.56.160) port 8080 (#0)
> POST /loginJSON HTTP/1.1
> User-Agent: curl/7.29.0
> Host: 192.168.56.160:8080
> Accept: */*
> content-type: application/json
> Content-Length: 35
>
* upload completely sent off: 35 out of 35 bytes
< HTTP/1.1 200 OK
< Content-Type: application/json; charset=utf-8
< Date: Wed, 11 Jul 2018 16:15:12 GMT
< Content-Length: 30
<
* Connection #0 to host 192.168.56.160 left intact
{"status":"you are logged in"}[vagrant@h105 ~]$
[vagrant@h105 ~]$
[vagrant@h105 ~]$ curl -v -X POST http://192.168.56.160:8080/loginForm -H 'content-type: application/json' -d '{ "user": "manu" ,"password":"123"}'
* About to connect() to 192.168.56.160 port 8080 (#0)
* Trying 192.168.56.160...
* Connected to 192.168.56.160 (192.168.56.160) port 8080 (#0)
> POST /loginForm HTTP/1.1
> User-Agent: curl/7.29.0
> Host: 192.168.56.160:8080
> Accept: */*
> content-type: application/json
> Content-Length: 35
>
* upload completely sent off: 35 out of 35 bytes
< HTTP/1.1 200 OK
< Content-Type: application/json; charset=utf-8
< Date: Wed, 11 Jul 2018 16:15:27 GMT
< Content-Length: 30
<
* Connection #0 to host 192.168.56.160 left intact
{"status":"you are logged in"}[vagrant@h105 ~]$
[vagrant@h105 ~]$
[vagrant@h105 ~]$ curl -v -X POST http://192.168.56.160:8080/loginForm -H 'content-type: text/plain' -d 'user=manu&password=123'
* About to connect() to 192.168.56.160 port 8080 (#0)
* Trying 192.168.56.160...
* Connected to 192.168.56.160 (192.168.56.160) port 8080 (#0)
> POST /loginForm HTTP/1.1
> User-Agent: curl/7.29.0
> Host: 192.168.56.160:8080
> Accept: */*
> content-type: text/plain
> Content-Length: 22
>
* upload completely sent off: 22 out of 22 bytes
< HTTP/1.1 400 Bad Request
< Content-Type: application/json; charset=utf-8
< Date: Wed, 11 Jul 2018 16:15:34 GMT
< Content-Length: 182
<
* Connection #0 to host 192.168.56.160 left intact
{"error":"Key: 'Login.User' Error:Field validation for 'User' failed on the 'required' tag\nKey: 'Login.Password' Error:Field validation for 'Password' failed on the 'required' tag"}[vagrant@h105 ~]$
[vagrant@h105 ~]$
[vagrant@h105 ~]$ curl -v -X POST http://192.168.56.160:8080/loginForm -H 'content-type: application/json' -d '{"password":"123","user": "manu_test" }'
* About to connect() to 192.168.56.160 port 8080 (#0)
* Trying 192.168.56.160...
* Connected to 192.168.56.160 (192.168.56.160) port 8080 (#0)
> POST /loginForm HTTP/1.1
> User-Agent: curl/7.29.0
> Host: 192.168.56.160:8080
> Accept: */*
> content-type: application/json
> Content-Length: 39
>
* upload completely sent off: 39 out of 39 bytes
< HTTP/1.1 401 Unauthorized
< Content-Type: application/json; charset=utf-8
< Date: Wed, 11 Jul 2018 16:16:09 GMT
< Content-Length: 25
<
* Connection #0 to host 192.168.56.160 left intact
{"status":"unauthorized"}[vagrant@h105 ~]$
[vagrant@h105 ~]$
[vagrant@h105 ~]$ curl -v -X POST http://192.168.56.160:8080/loginForm -H 'content-type: application/json' -d '{"password":"123","user": "manu" }'
* About to connect() to 192.168.56.160 port 8080 (#0)
* Trying 192.168.56.160...
* Connected to 192.168.56.160 (192.168.56.160) port 8080 (#0)
> POST /loginForm HTTP/1.1
> User-Agent: curl/7.29.0
> Host: 192.168.56.160:8080
> Accept: */*
> content-type: application/json
> Content-Length: 34
>
* upload completely sent off: 34 out of 34 bytes
< HTTP/1.1 200 OK
< Content-Type: application/json; charset=utf-8
< Date: Wed, 11 Jul 2018 16:16:17 GMT
< Content-Length: 30
<
* Connection #0 to host 192.168.56.160 left intact
{"status":"you are logged in"}[vagrant@h105 ~]$
[vagrant@h105 ~]$
[vagrant@h105 ~]$ curl -v -X POST http://192.168.56.160:8080/loginForm -H 'content-type: application/xml' -d '<user>manu</user><password>123</password>'
* About to connect() to 192.168.56.160 port 8080 (#0)
* Trying 192.168.56.160...
* Connected to 192.168.56.160 (192.168.56.160) port 8080 (#0)
> POST /loginForm HTTP/1.1
> User-Agent: curl/7.29.0
> Host: 192.168.56.160:8080
> Accept: */*
> content-type: application/xml
> Content-Length: 41
>
* upload completely sent off: 41 out of 41 bytes
< HTTP/1.1 400 Bad Request
< Content-Type: application/json; charset=utf-8
< Date: Wed, 11 Jul 2018 16:18:09 GMT
< Content-Length: 182
<
* Connection #0 to host 192.168.56.160 left intact
{"error":"Key: 'Login.User' Error:Field validation for 'User' failed on the 'required' tag\nKey: 'Login.Password' Error:Field validation for 'Password' failed on the 'required' tag"}[vagrant@h105 ~]$
[vagrant@h105 ~]$
[vagrant@h105 ~]$ curl -v -X POST http://192.168.56.160:8080/loginForm --form user=manu --form password=123
* About to connect() to 192.168.56.160 port 8080 (#0)
* Trying 192.168.56.160...
* Connected to 192.168.56.160 (192.168.56.160) port 8080 (#0)
> POST /loginForm HTTP/1.1
> User-Agent: curl/7.29.0
> Host: 192.168.56.160:8080
> Accept: */*
> Content-Length: 243
> Expect: 100-continue
> Content-Type: multipart/form-data; boundary=----------------------------bc8cf04c4143
>
< HTTP/1.1 100 Continue
< HTTP/1.1 200 OK
< Content-Type: application/json; charset=utf-8
< Date: Thu, 19 Jul 2018 03:26:39 GMT
< Content-Length: 30
<
* Connection #0 to host 192.168.56.160 left intact
{"status":"you are logged in"}[vagrant@h105 ~]$
[vagrant@h105 ~]$
[vagrant@h105 ~]$
结果同时输出到了客户端和console
服务端的目标路径里也多了一个日志文件 gin.log,并且创建时间也是吻合的
[vagrant@h160 go]$ ls
bin gin.log hello.go pkg src
[vagrant@h160 go]$ cat gin.log
[GIN] 2018/07/11 - 16:14:57 | 400 | 1.487198ms | 192.168.56.105 | POST /loginJSON
[GIN] 2018/07/11 - 16:15:12 | 200 | 193.097µs | 192.168.56.105 | POST /loginJSON
[GIN] 2018/07/11 - 16:15:27 | 200 | 181.733µs | 192.168.56.105 | POST /loginForm
[GIN] 2018/07/11 - 16:15:34 | 400 | 368.599µs | 192.168.56.105 | POST /loginForm
[GIN] 2018/07/11 - 16:16:09 | 401 | 134.971µs | 192.168.56.105 | POST /loginForm
[GIN] 2018/07/11 - 16:16:17 | 200 | 140.609µs | 192.168.56.105 | POST /loginForm
[GIN] 2018/07/11 - 16:18:09 | 400 | 225.385µs | 192.168.56.105 | POST /loginForm
[vagrant@h160 go]$
内容与 console 中的输出是一样的,如果通过终端查看,客户访问的过程中,可以发现一前一后的实时记录变化
构建一个简单的 web 还是非常快捷的
可以通过 Bind 的方法初始化 module
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。