gin框架是基於golang語言的web框架。如果用gin實現服務,有下述的場景需求,那麼可以繼續閱覽:
- 服務針對不同的路由,有不同的驗證規則。比如服務對應PC管理端和移動端,分別有不同的驗證規則,涉及路由組、中間件攔截驗證;
- 請求記錄、操作日誌按照時間每天記錄到文件中。涉及中間件日誌操作;
- 跨域問題,涉及中間件跨域;
- API的使用,涉及常用的POST,PUT,GET,DELETE。
代碼示意:
package main
import (
"encoding/json"
"errors"
"fmt"
"net/http"
"os"
"strconv"
"time"
"github.com/gin-gonic/gin"
)
type User struct {
Name string `json:"name"`
Age int `json:"age"`
}
func main(){
gin.SetMode(gin.DebugMode)
router := gin.New()
router.Use(LoggerByTime())//中間件:日誌
router.Use(gin.Recovery())
router.Use(Cors())//中間件:跨域
api:=router.Group("/pc").Use(AuthRequiredPc)//pc開頭的路由中間件:驗證
{
api.POST("/add", func(c *gin.Context) {//參數方式:body
var (
user User
rtn Rtn
)
err := c.ShouldBindJSON(&user)
if err != nil {
fmt.Fprintln(GetLogFileName(), "Add:"+err.Error())
rtn.R = 0
rtn.Err = err.Error()
c.JSON(http.StatusInternalServerError,rtn)
panic(err)
return
}
fmt.Fprintln(GetLogFileName(), "添加了一個用戶,名="+user.Name+",年齡="+strconv.Itoa(user.Age))
rtn.R = 1
c.JSON(http.StatusOK,rtn)
})
api.PUT("/edit", func(c *gin.Context) {//參數方式:body
var (
user User
rtn Rtn
)
err := c.ShouldBindJSON(&user)
if err != nil {
fmt.Fprintln(GetLogFileName(), "Edit:"+err.Error())
rtn.R = 0
rtn.Err = err.Error()
c.JSON(http.StatusInternalServerError,rtn)
panic(err)
return
}
fmt.Fprintln(GetLogFileName(), "編輯了用戶,名="+user.Name+",年齡="+strconv.Itoa(user.Age))
rtn.R = 1
c.JSON(http.StatusOK,rtn)
})
api.DELETE("/del", func(c *gin.Context) {//參數方式:post form
var rtn Rtn
name := c.PostForm("name")
fmt.Fprintln(GetLogFileName(), "刪除用戶名="+name)
rtn.R = 1
c.JSON(http.StatusOK,rtn)
})
}
apiOut:=router.Group("/mobile").Use(AuthRequiredMobile)//mobile開頭的路由中間件:驗證
{
apiOut.GET("/detail", func(c *gin.Context) {//參數方式:query
var rtn Rtn
name := c.Query("name")
fmt.Fprintln(GetLogFileName(), "詳情:"+"該用戶名="+name)
rtn.R = 1
c.JSON(http.StatusOK,rtn)
})
}
router.Run(":8888")
}
//中間件:日誌。參考gin自帶的日誌中間件實現日誌按照天存儲,詳見gin/logger.go部分
func GetLogFileName()*os.File{
filename:=fmt.Sprintf("./%s",time.Now().Format("20060102"))
fileObj,_ := os.OpenFile(filename,os.O_RDWR|os.O_CREATE|os.O_APPEND,0777)
return fileObj
}
type logger struct{
Time string// Time shows the time after the server returns a response.
StatusCode int// StatusCode is HTTP response code.
Latency string// Latency is how much time the server cost to process a certain request.
ClientIP string// ClientIP equals Context's ClientIP method.
Method string// Method is the HTTP method given to the request.
Path string// Path is a path the client requests.
}
func LoggerByTime() gin.HandlerFunc {
return func(c *gin.Context) {
// Start timer
start := time.Now()
path := c.Request.URL.Path
raw := c.Request.URL.RawQuery
// Process request
c.Next()
param := logger{}
// Stop timer
param.Time = time.Now().Format("2006-01-02 15:04:05")
param.Latency = fmt.Sprintf("%dms",time.Now().Sub(start).Nanoseconds()/1e6)
param.ClientIP = c.ClientIP()
param.Method = c.Request.Method
param.StatusCode = c.Writer.Status()
if raw != "" {
path = path + "?" + raw
}
param.Path = path
paramStr, _ := json.Marshal(param)
fmt.Fprintln(GetLogFileName(), string(paramStr))
}
}
//中間件:跨域。可根據自己需求進行調整
func Cors() gin.HandlerFunc {
return func(c *gin.Context) {
method := c.Request.Method
origin := c.Request.Header.Get("Origin")
if origin != "" {
c.Header("Access-Control-Allow-Origin", "*")
c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
c.Header("Access-Control-Allow-Headers", "Origin,Authorization,Content-Length,Content-Type,Date,DataField")
c.Header("Access-Control-Max-Age", "3600")
c.Header("Access-Control-Allow-Credentials", "true")
}
if method == "OPTIONS" {
c.JSON(http.StatusOK, "Options Request!")
}
c.Next()
}
}
//中間件:攔截校驗
//攔截校驗
type Rtn struct {
R int `json:"r"`
Data interface{} `json:"data"`
Err string `json:"err"`
}
func AuthRequiredPc(c *gin.Context){
var rtn Rtn
var err error
authorization := c.Request.Header.Get("Authorization")
if authorization != "pc"{
rtn.Data=0
err = errors.New("authen error!")
fmt.Fprintln(GetLogFileName(), "AuthRequired:"+err.Error())
rtn.Err = err.Error()
c.JSON(http.StatusInternalServerError,rtn)
panic(err)
return
}
}
func AuthRequiredMobile(c *gin.Context){
var rtn Rtn
var err error
authorization := c.Request.Header.Get("Authorization")
if authorization != "mobile"{
rtn.Data=0
err = errors.New("authen error!")
fmt.Fprintln(GetLogFileName(), "AuthRequired:"+err.Error())
rtn.Err = err.Error()
c.JSON(http.StatusInternalServerError,rtn)
panic(err)
return
}
}