本篇是mygin的第七篇,参照gin框架,感兴趣的可以从
Mygin第一篇
开始看,Mygin从零开始完全手写,在实现的同时,带你一窥gin框架的核心原理实现。

目的

  • 中间件Middleware优化
  • 默认log日志中间件
    在上篇
    Mygin实现中间件Middleware
    中间件Middleware很生硬,完全依赖循环,如果某个中间件想要cover住全部中间件,比如我想记录,整个请求的耗时时间,以便针对优化的功能。因此需要把之前生硬的方式做一些修改。

修改

1.实例化上下文修改
//实例化一个下上文
	c := &Context{
		Request:  r,
		Writer:   w,
		Params:   params,
		handlers: handlers,
		index:    -1, //默认下标为-1
	}
2.修改上下文Next方法
// Next 执行链中的剩余处理程序。
func (c *Context) Next() {
	c.index++
	//遍历handlers
	for c.index < int8(len(c.handlers)) {
		//真正调用执行handler方法
		c.handlers[c.index](c)
		c.index++
	}
}

日志

参照(复制)gin中的写法,新建mygin/logger.go日志中间件文件。

  • mygin/logger.go
package mygin

import (
	"fmt"
	"net/http"
	"time"
)

const (
	green   = "\033[97;42m" // 绿色
	white   = "\033[90;47m" // 白色
	yellow  = "\033[90;43m" // 黄色
	red     = "\033[97;41m" // 红色
	blue    = "\033[97;44m" // 蓝色
	magenta = "\033[97;45m" // 洋红色
	cyan    = "\033[97;46m" // 青色
	reset   = "\033[0m"     // 重置颜色
)

type LogFormatterParams struct {
}

// MethodColor 方法颜色获取
func (l *LogFormatterParams) MethodColor(method string) string {
	switch method {
	case http.MethodGet:
		return blue
	case http.MethodPost:
		return cyan
	case http.MethodPut:
		return yellow
	case http.MethodDelete:
		return red
	case http.MethodPatch:
		return green
	case http.MethodHead:
		return magenta
	case http.MethodOptions:
		return white
	default:
		return reset
	}
}

// StatusCodeColor 状态颜色获取
func (l *LogFormatterParams) StatusCodeColor(code int) string {
	switch {
	case code >= http.StatusOK && code < http.StatusMultipleChoices:
		return green
	case code >= http.StatusMultipleChoices && code < http.StatusBadRequest:
		return white
	case code >= http.StatusBadRequest && code < http.StatusInternalServerError:
		return yellow
	default:
		return red
	}
}

// LoggerFunc 记录日志的方法
func (l *LogFormatterParams) LoggerFunc() HandlerFunc {
	return func(context *Context) {
		// 启动时间
		start := time.Now()

		// 后续处理请求
		context.Next()

        //后续处理请求 结束时间
		now := time.Now()

		str := fmt.Sprintf("[MyGIN] %v |%s %3d %s| %13v  |%s %-7s %s %#v\n",
			now.Format("2006/01/02 - 15:04:05"),
			l.StatusCodeColor(context.status), context.status, reset,
			now.Sub(start), //耗时
			l.MethodColor(context.Request.Method), context.Request.Method, reset,
			context.Request.URL.Path,
		)
		fmt.Println(str)
	}
}

日志中间件

测试

测试代码

package mygin

import (
	"net/http"
	"path"
	"testing"
)

func TestMyGin06(t *testing.T) {
	r := Default()
	r.Use()
	//测试需要登录
	group := r.Group("/api", func(context *Context) {
		//todo....
		context.String(http.StatusOK, "api Group 中间件失败了....\n")
		context.Abort()
	})

	group.Use()

	//这个回调不会执行
	group.GET("/hello/:name", func(context *Context) {
		name := context.Params.ByName("name")
		context.String(http.StatusOK, path.Join("hello ", name, "!"))
	})

	//测试没有发生Abort
	group2 := r.Group("/api2", func(context *Context) {
		//todo....
		context.String(http.StatusOK, "api Group 中间件成功了....\n")
	})

	//这个回调会执行
	group2.GET("/hello2/:name", func(context *Context) {
		name := context.Params.ByName("name")
		context.String(http.StatusOK, path.Join("hello2 ", name, "!\n"))
	})

	// 启动服务器并监听端口
	r.Run(":8088")
}
启动测试
go test
curl请求测试
curl -i http://localhost:8088/api2/hello2/scott
HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8
Date: Tue, 30 Jan 2024 06:56:03 GMT
Content-Length: 49

api Group 中间件成功了....
hello2 /scott/!
➜  ~ curl -i http://localhost:8088/api/hello/scott
HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8
Date: Tue, 30 Jan 2024 06:56:26 GMT
Content-Length: 33

api Group 中间件失败了....
查看控制台输出

标签: none

添加新评论