Gin 框架搭建一个 HTTP 网络服务简洁代码

Gin

Gin 是一个 golang 的微框架,封装比较优雅,API 友好,源码注释比较明确,已经发布了 1.0 版本。具有快速灵活,容错方便等特点。其实对于 golang 而言,web 框架的依赖要远比 Python,Java之类的要小。自身的 net/http 足够简单,性能也非常不错。框架更像是一些常用函数或者工具的集合。借助框架开发,不仅可以省去很多常用的封装带来的时间,也有助于团队的编码风格和形成规范。

首先需要安装,安装比较简单,使用 go get 即可

go get gopkg.in/gin-gonic/gin.v1

Gin 的版本托管再 gopkg 的网站上。我在安装的过程中,gokpg 卡住了,后来不得不根据 gin 里的 godep 的文件,把响应的源码从 github 上下载,然后 copy 到对应的目录。

关于 golang 的包管理和依赖,我们以后再讨论。
以下是我写的一个 POST 请求响应验证

package main

import (
    "fmt"
    "sort"
    "sync"
    "time"
    "errors"
    "net/http"
    "crypto/md5"
    "encoding/hex"

    "gopkg.in/gin-gonic/gin.v1"
    "gopkg.in/cihub/seelog.v2"
)

type State int

const (
    StateOK                     State = iota
    StateContentTypeMismatch    State = 1000 + iota
    StateSignatureMismatch
    StateIdentifierMismatch
)

type StateMap map[State]string

var StateMapping  = StateMap{
    StateOK:                     "Success",
    StateContentTypeMismatch:    "Content mismatch",
    StateSignatureMismatch:      "Signature mismatch",
    StateIdentifierMismatch:     "Identifier mismatch",
}

var ContentTypeErr = errors.New("ContentTypeErr is not json object")

type Data struct {
    Identifier  string  `json:"identifier" binding:"required"`
    Signature   string  `json:"signature"  binding:"required"`
    DataStr     string  `json:"data_str"`
}

func srvHandlerPost(c *gin.Context) {

    var (
        dat Data
        err error
        code State = StateOK
    )

    // handler 结束处理后返回响应体给 client 端
    defer func (c *gin.Context, state *State) {
        code := *state
        seelog.Debugf("State: %d", code)
        status, ok := StateMapping[code]
        if !ok {
            seelog.Errorf("Unknown code state: %d", code)
        }

        c.JSON(http.StatusOK, gin.H{
            "code":     code,
            "status":   status,
        })
    }(c, &code)


    // 验证 content type 并解析 body
    contentType := c.Request.Header.Get("Content-Type")
    switch contentType {

    case "application/json":
        if err := c.BindJSON(&dat); err != nil {
            seelog.Error("BindJSON failed, err: %v", err)
        }

    default:
        err = ContentTypeErr
        code = StateContentTypeMismatch
        seelog.Errorf("contentType mismatch: %s", contentType)
        return
    }

    // 验证 identifier 身份
    if dat.Identifier != "owenliu" {
        code = StateIdentifierMismatch
        seelog.Errorf("identifier mismatch: %s", dat.Identifier)
        return
    }

    // 验证签名
    dataMap := gin.H{
        "identifier":   dat.Identifier,
        "data_str":     dat.DataStr,
    }

    paramStr := "4534253453252345353534253453245342"
    var keys []string

    for key := range dataMap {
        keys = append(keys, key)
    }

    sort.Strings(keys)

    for _, key := range keys {
        paramStr += key + dataMap[key].(string)
    }

    md5Ctx := md5.New()
    _, err = md5Ctx.Write( []byte( paramStr ) )
    if err != nil {
        seelog.Errorf("calc md5 write failed, err: %v", err)
    }

    sign := hex.EncodeToString( md5Ctx.Sum( nil ) )

    if sign != dat.Signature {
        code = StateSignatureMismatch
        seelog.Errorf("Signature mismatch: recv: %s, calc: %s, paramStr: %s", dat.Signature, sign, paramStr)
        return
    }
}

func StartSrv(){

    seelog.Debug("我爱北京天安门!")

    postRouter := gin.Default()

    postRouter.POST("/srv_post", srvHandlerPost)

    postRouter.Run(":8000")

    seelog.Debug("天安门上太阳升!")
}

func main(){

    StartSrv()
}

参考文章: https://www.cnblogs.com/xielideboke/p/golang.html

猜你喜欢

转载自blog.csdn.net/u010649766/article/details/80323882