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()
}