中间件实践

中间件最大的作用,莫过于用于一些记录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的进程。

results matching ""

    No results matching ""