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