8.1技术学习总结 | 青训营

100 阅读6分钟

侧重记录在听课过程中自己的一些思考和学习路径

ep9 走进 HTTP 协议

ep9.1 Postman 14:01

熟悉操作

ep9.2 请求流程

ep10 HTTP 框架的设计与实现

ep10.1 分层设计 1:20(与ep9.2联系)

七层网络模型,也称为OSI(Open Systems Interconnection)模型,四层网络模型是一种简化版的网络模型,也称为TCP/IP模型或传输层/网络层模型。与七层网络模型相比,它将网络通信分为四个层次,更加精简,但仍能有效描述网络通信的基本过程。其中每一层分别有自己相对应的网络协议。

用户层-中间件层(预处理和后处理)-路由层-协议层-网络层

common层

层与层之间通过接口联系

下面详细介绍了各层

ep10.2 中间件设计 12:33

func main() {
    // 创建一个新的服务器实例 h
    h := server.New()

    // 定义处理 "/login" 路由的处理器
    h.POST("/login", func(c context.Context, ctx *app.RequestContext) {
        // 打印收到的请求信息
        logs.Infof("Received RawRequest: %s", ctx.Request.RawRequest())
        // 执行一些业务逻辑
        ctx.JSON(200, "OK")
        // 打印响应信息
        logs.Infof("Send RawResponse: %s", ctx.Response.RawResponse())
    })

    // 定义处理 "/logout" 路由的处理器
    h.POST("/logout", func(c context.Context, ctx *app.RequestContext) {
        // 打印收到的请求信息
        logs.Infof("Received RawRequest: %s", ctx.Request.RawRequest())
        // 执行一些业务逻辑
        ctx.JSON(200, "OK")
        // 打印响应信息
        logs.Infof("Send RawResponse: %s", ctx.Response.RawResponse())
    })

    // 启动服务器
    h.Spin()
}
func main() {
    // 创建一个新的服务器实例 h
    h := server.New()

    // 定义处理 "/login" 路由的处理器
    h.POST("/login", func(c context.Context, ctx *app.RequestContext) {
        // 打印收到的请求信息
        logs.Infof("Received RawRequest: %s", ctx.Request.RawRequest())
        // 执行一些业务逻辑
        ctx.JSON(200, "OK")
        // 打印响应信息
        logs.Infof("Send RawResponse: %s", ctx.Response.RawResponse())
    })

    // 定义处理 "/logout" 路由的处理器
    h.POST("/logout", func(c context.Context, ctx *app.RequestContext) {
        // 打印收到的请求信息
        logs.Infof("Received RawRequest: %s", ctx.Request.RawRequest())
        // 执行一些业务逻辑
        ctx.JSON(200, "OK")
        // 打印响应信息
        logs.Infof("Send RawResponse: %s", ctx.Response.RawResponse())
    })

    // 启动服务器
    h.Spin()
}

两段代码都实现了一个简单的应用程序,包含了两个路由处理器(login和logout)。区别在于第一段代码在每个处理器中都包含了日志打印代码,导致代码冗余较高;而第二段代码引入了中间件函数,将日志打印与业务逻辑分离,减少了代码冗余,使得代码结构更加清晰和灵活。使用中间件可以提高代码的可维护性和可扩展性,并将公共逻辑抽象出来,使得处理器中只关注业务逻辑,而不用关心其他非业务相关的代码。

ep11 性能修炼之道

课后作业

  1. 为什么HTTP框架要分层设计?

HTTP框架之所以采用分层设计,是为了将不同的功能和责任划分到不同的模块中,使得框架的设计更加清晰、灵活和可扩展。分层设计有助于降低代码的耦合性,提高代码的复用性和可维护性,同时也有利于团队合作开发。

优势:

  • 模块化:分层设计将功能划分为不同的模块,使得每个模块的职责清晰,易于维护和扩展。
  • 可复用性:不同的模块可以独立设计,使得某些功能可以在多个地方重复使用,提高了代码的复用性。
  • 易于测试:分层设计将功能分散在不同模块中,可以更容易地对每个模块进行单元测试和集成测试。
  • 团队协作:分层设计明确了每个模块的职责,使得团队成员可以独立开发不同的模块,提高了团队协作效率。

劣势:

  • 复杂性:分层设计可能会导致框架的结构变得更加复杂,需要合理划分模块之间的依赖关系。
  • 性能:分层设计可能会引入一定的性能开销,因为需要在不同模块之间进行通信和数据传递。
  1. 现有开源社区HTTP框架的优势与不足:

不同的开源社区HTTP框架具有不同的优势和不足,以下是一些常见的优势和不足:

优势:

  • 高性能:一些HTTP框架专注于性能优化,使用高效的算法和数据结构,以提供卓越的性能。
  • 简单易用:一些HTTP框架设计简洁,易于上手使用,适合快速开发和小型项目。
  • 功能丰富:一些HTTP框架提供了丰富的功能和组件,涵盖了路由、中间件、模板引擎、ORM等,适用于构建复杂的Web应用。
  • 社区支持:受欢迎的HTTP框架通常有活跃的开源社区,可以获得更多的支持和社区贡献。

不足:

  • 学习曲线:一些HTTP框架可能有较大的学习曲线,需要较长时间来熟悉其设计和使用方式。
  • 过度设计:一些HTTP框架可能过度设计,引入了许多不必要的复杂性和功能,增加了学习和使用的难度。
  • 性能瓶颈:一些HTTP框架可能在高并发场景下存在性能瓶颈,需要进一步优化。
  • 兼容性:一些HTTP框架可能对不同版本的Go语言或不同操作系统的兼容性存在一定问题。
  1. 中间件还有没有其他实现方式?可以用伪代码说明。

除了常见的基于函数调用的中间件实现方式外,还可以使用类似于装饰器模式的方式来实现中间件。在这种方式下,我们可以定义一个接口或函数类型,用于表示中间件的行为,然后通过装饰器模式将中间件逐层包装,从而实现对请求和响应的处理。

伪代码示例:

// 中间件接口
type Middleware interface {
    Handle(next http.Handler) http.Handler
}

// 实现一个具体的中间件
type LoggingMiddleware struct{}

func (m LoggingMiddleware) Handle(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        log.Println("Received request:", r.Method, r.URL.Path)
        next.ServeHTTP(w, r)
        log.Println("Sent response:", r.Method, r.URL.Path)
    })
}

// 使用装饰器模式包装中间件
func UseMiddleware(h http.Handler, middleware ...Middleware) http.Handler {
    for i := len(middleware) - 1; i >= 0; i-- {
        h = middleware[i].Handle(h)
    }
    return h
}

// 使用示例
func main() {
    router := http.NewServeMux()
    router.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("Hello, World!"))
    })

    // 应用中间件
    loggingMiddleware := LoggingMiddleware{}
    handler := UseMiddleware(router, loggingMiddleware)

    http.ListenAndServe(":8080", handler)
}
  1. 完成基于前缀路由树的注册与查找功能?可以用伪代码说明。

前缀路由树(Prefix Tree)是一种高效的路由匹配数据结构,它可以用于快速查找匹配某个URL路径的处理器。

伪代码示例:

// 路由节点
type RouteNode struct {
    path     string
    handler  http.HandlerFunc
    children map[string]*RouteNode
}

// 创建路由节点
func NewRouteNode(path string, handler http.HandlerFunc) *RouteNode {
    return &RouteNode{
        path:     path,
        handler:  handler,
        children: make(map[string]*RouteNode),
    }
}

// 注册路由
func (node *RouteNode) AddRoute(path string, handler http.HandlerFunc) {
    if path == "" {
        node.handler = handler
        return
    }

    parts := strings.SplitN(path, "/", 2)
    childPath := parts[0]
    remainingPath := ""
    if len(parts) > 1 {
        remainingPath = parts[1]
    }

    child, ok := node.children[childPath]
    if !ok {
        child = NewRouteNode(childPath, nil)
        node.children[childPath]

 = child
    }

    child.AddRoute(remainingPath, handler)
}

// 查找路由
func (node *RouteNode) FindRoute(path string) (http.HandlerFunc, bool) {
    if path == "" {
        return node.handler, true
    }

    parts := strings.SplitN(path, "/", 2)
    childPath := parts[0]
    remainingPath := ""
    if len(parts) > 1 {
        remainingPath = parts[1]
    }

    child, ok := node.children[childPath]
    if !ok {
        return nil, false
    }

    return child.FindRoute(remainingPath)
}

// 使用示例
func main() {
    router := NewRouteNode("", nil)
    router.AddRoute("/hello", func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("Hello, World!"))
    })
    router.AddRoute("/about", func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("This is the about page."))
    })

    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        handler, ok := router.FindRoute(r.URL.Path)
        if !ok {
            http.NotFound(w, r)
            return
        }

        handler(w, r)
    })

    http.ListenAndServe(":8080", nil)
}
  1. 路由还有没有其他的实现方式?

除了基于前缀路由树的实现方式外,还有其他常见的路由实现方式,包括正则表达式路由、基于字典树的路由和基于哈希表的路由等。每种实现方式都有其特点和适用场景。选择合适的路由实现方式取决于具体的应用需求和性能要求。