go之web框架gin

一、gin简介

        Gin 是一个 go 写的 web 框架,具有高性能的优点。

二、快速使用

2.1 引入依赖
go get -u github.com/gin-gonic/gin
2.2 示例代码
type User struct {
	USERNAME string `json:"username"`
}

func main() {
	router := gin.Default()
	router.POST("/hello", func(c *gin.Context) {
		var user User
		c.Bind(&user)
		c.JSON(200, gin.H{
			"user": user,
		})
	})
	router.Run(":8080")
}
2.3验证

2.4 中间件
2.4.0 wrapper middle
type responseWriter struct {
	gin.ResponseWriter
	body *bytes.Buffer
}

func (rw responseWriter) Write(p []byte) (n int, err error) {
	rw.body.Write(p)
	return rw.ResponseWriter.Write(p)
}

func WrapperMiddle() gin.HandlerFunc {
	return func(c *gin.Context) {
		// 记录请求体
		bodyBytes, _ := io.ReadAll(c.Request.Body)
		// 替换请求体,可重复读
		c.Request.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))

		// 替换writer, 可以获取body
		c.Writer = &responseWriter{
			ResponseWriter: c.Writer,
			body:           bytes.NewBufferString(""),
		}

	}
}
2.4.1 access log 中间件


func LogMiddle() gin.HandlerFunc {
	return func(c *gin.Context) {
		start := time.Now()
		path := c.Request.URL.Path
		method := c.Request.Method
		// 记录请求体
		bodyBytes, _ := io.ReadAll(c.Request.Body)

		// 请求处理
		c.Next()

		// 打印日志
		reqBody := string(bodyBytes)
        // 如果请求body 含有 password,则替换为****
		reqBody = strings.ReplaceAll(reqBody, "password", "****")
		

		respBody := string(c.Writer.(*responseWriter).body.Bytes())

		slog.Info("method:[%s] path:%s reqBody:%s respBOdy:%s duration:%s\n", method, path, reqBody, respBody, time.Since(start))
	}
}
2.4.2 recover中间件
func RecoverMiddle() gin.HandlerFunc {
	return func(c *gin.Context) {
		bodyBytes, _ := io.ReadAll(c.Request.Body)
		// 替换请求体,可重复读
		c.Request.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
		req := string(bodyBytes)

		defer func(c *gin.Context) {
			if err := recover(); err != nil {
				// 打印错误日志
				fmt.Printf("error:%v,path:%s body:%s", err, c.Request.URL.Path, req)
				// http 请求返回错误
				c.AbortWithStatusJSON(http.StatusInternalServerError, map[string]interface{}{"code": "InnerError", "msg": "出现内部错误"})
			}
		}(c)
		c.Next()
	}
}
2.4.3 cors 中间件
func CorsMiddle() gin.HandlerFunc {
	corsConfig := struct {
		AllowOrigins []string
		AllowMethods []string
	}{
		AllowOrigins: []string{"baidu.com","vicyor.com"},
		AllowMethods: []string{"POST","GET", "OPTIONS"},
	}
	return func(c *gin.Context) {

		// 判断是否跨域
		if origin := c.Request.Header.Get("Origin"); len(origin) > 0 {
			oUrl,_ := url.Parse(origin)
			oHost := oUrl.Host
			oPort := oUrl.Port()
			oScheme :=oUrl.Scheme
			// 非同源
			if oHost != "vicyor.com" || (oScheme != "http" && oPort != "8080") || (oScheme != "https" && oPort != "443"){
				if !slices.Contains(corsConfig.AllowOrigins, oHost) {
					c.AbortWithStatusJSON(http.StatusForbidden, c.Header)
					return
				}
				if !slices.Contains(corsConfig.AllowMethods, c.Request.Method) {
					c.AbortWithStatusJSON(http.StatusForbidden, c.Header)
					return
				}
			}
		}

		c.Header("Access-Control-Allow-Origin", strings.Join(corsConfig.AllowOrigins, ","))
		// 允许凭证,包括cookie 和 authorization
		c.Header("Access-Control-Allow-Credentials", "true")
		c.Header("Access-Control-Allow-Methods", strings.Join(corsConfig.AllowMethods, ","))
		c.Header("Access-Control-Allow-Headers", "Authorization,Content-Type")

		// 没有跨域,option请求直接返回
		if c.Request.Method == "OPTIONS" { // 如果是预检请求,直接返回
			c.AbortWithStatus(http.StatusNoContent)
			return
		}

	}
}

1. 判断是否同源,如果同源,直接通过。

2.非同源,判断host,method是否在自定义跨域配置中。

   若不在,返回403

3.判断是否是option请求,如果是option请求,直接返回200 + 没有内容。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值