中间件实践
中间件最大的作用,莫过于用于一些记录log,错误handler,还有就是对部分接口的鉴权。下面就实现一个简易的鉴权中间件。
router.GET(
"/auth/signin"
, func(c *gin.Context) {
cookie :=
&
http.Cookie{
Name:
"session_id"
,
Value:
"123"
,
Path:
"/"
,
HttpOnly:
true
,
}
http.SetCookie(c.Writer, cookie)
c.String(http.StatusOK,
"Login successful"
)
})
router.GET(
"/home"
, AuthMiddleWare(), func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"data"
:
"home"
})
})
登录函数会设置一个session_id的cookie,注意这里需要指定path为/,不然gin会自动设置cookie的path为/auth,一个特别奇怪的问题。/homne的逻辑很简单,使用中间件AuthMiddleWare注册之后,将会先执行AuthMiddleWare的逻辑,然后才到/home的逻辑。
AuthMiddleWare的代码如下:
func
AuthMiddleWare
()
gin.HandlerFunc
{
return
func(c *gin.Context) {
if
cookie, err := c.Request.Cookie(
"session_id"
); err == nil {
value := cookie.Value
fmt.Println(value)
if
value ==
"123"
{
c.Next()
return
}
}
c.JSON(http.StatusUnauthorized, gin.H{
"error"
:
"Unauthorized"
,
})
c.Abort()
return
}
}
从上下文的请求中读取cookie,然后校对cookie,如果有问题,则终止请求,直接返回,这里使用了c.Abort()方法。
In [
7
]: resp = requests.get(
'http://127.0.0.1:8000/home'
)
In [
8
]: resp.json()
Out[
8
]: {
u'error'
:
u'Unauthorized'
}
In [
9
]: login = requests.get(
'http://127.0.0.1:8000/auth/signin'
)
In [
10
]: login.cookies
Out[
10
]:
<
RequestsCookieJar[Cookie(version=
0
, name=
'session_id'
, value=
'123'
, port=
None
, port_specified=
False
, domain=
'127.0.0.1'
, domain_specified=
False
, domain_initial_dot=
False
, path=
'/'
, path_specified=
True
, secure=
False
, expires=
None
, discard=
True
, comment=
None
, comment_url=
None
, rest={
'HttpOnly'
:
None
}, rfc2109=
False
)]
>
In [
11
]: resp = requests.get(
'http://127.0.0.1:8000/home'
, cookies=login.cookies)
In [
12
]: resp.json()
Out[
12
]: {
u'data'
:
u'home'
}
异步协程
golang的高并发一大利器就是协程。gin里可以借助协程实现异步任务。因为涉及异步过程,请求的上下文需要copy到异步的上下文,并且这个上下文是只读的。
router.GET(
"/sync"
, func(c *gin.Context) {
time.Sleep(
5
* time.Second)
log
.Println(
"Done! in path"
+ c.Request.URL.Path)
})
router.GET(
"/async"
, func(c *gin.Context) {
cCp := c.Copy()
go func() {
time.Sleep(
5
* time.Second)
log
.Println(
"Done! in path"
+ cCp.Request.URL.Path)
}()
})
在请求的时候,sleep5秒钟,同步的逻辑可以看到,服务的进程睡眠了。异步的逻辑则看到响应返回了,然后程序还在后台的协程处理。
自定义router
gin不仅可以使用框架本身的router进行Run,也可以配合使用net/http本身的功能:
func
main
() {
router
:= gin.
Default
()
http.
ListenAndServe
(
":8080"
, router)
}
或者
func
main
() {
router
:= gin.
Default
()
s :=
&
http.Server{
Addr:
":8000"
,
Handler: router,
ReadTimeout:
10
* time.Second,
WriteTimeout:
10
* time.Second,
MaxHeaderBytes:
1
<
<
20
,
}
s
.ListenAndServe
()
}
当然还有一个优雅的重启和结束进程的方案。后面将会探索使用supervisor管理golang的进程。