Golang Pkg Collection

Keep learning

Posted by lanbery on October 15, 2019

Usage pkg in Go world


net/http

Go 语言里面提供了一个完善的 net/http 包,通过 http 包可以很方便的就搭建起来一个可以运行的 Web 服务。同时使用这个包能很简单地对 Web 的路由,静态文件,模版,cookie 等数据进行设置和操作。

http包建立Web服务

package main

import (
    "fmt"
    "net/http"
    "strings"
    "log"
)

func sayhelloName(w http.ResponseWriter, r *http.Request) {

    r.ParseForm()   // 解析参数,默认不会解析的

    fmt.Println(r.Form) // 这些信息是输出到服务器端的

    fmt.Println("path",r.URL.path)
    fmt.Println("scheme",r.URL.Scheme)
    fmt.Println(r.Form["url_long"])

    for k,v := range r.Form {
        fmt.Println("key:",k)
        fmt.Println("Value:",strings.Join(v,""))
    }

    fmt.Fprintf(w,"Hello lanbery") // 写到w 输出到客户端的流
}

func main() {
    http.HandleFunc("/",sayhelloName)   // 设置路由

    err := http.ListenAndServe(":9099",nil) // 设置监听端口

    if err != nil {
        log.Fatal("Listen on 9099 serve :",err)
    }
}

web 工作方式的几个概念

- Request:用户请求的信息,用来解析用户的请求信息,包括 post、get、cookie、url 等信息
- Response:服务器需要反馈给客户端的信息
- Conn:用户的每次请求链接
- Handler:处理请求和生成返回信息的处理逻辑

Go 的 http 包的源码,通过下面的代码我们可以看到整个的 http 处理过程


func (srv *Server) Serve(l net.Listener) error {
    defer l.Close()
    var tempDelay time.Duration // how long to sleep on accept failure
    for {
        rw, e := l.Accept()
        if e != nil {
            if ne, ok := e.(net.Error); ok && ne.Temporary() {
                if tempDelay == 0 {
                    tempDelay = 5 * time.Millisecond
                } else {
                    tempDelay *= 2
                }
                if max := 1 * time.Second; tempDelay > max {
                    tempDelay = max
                }
                log.Printf("http: Accept error: %v; retrying in %v", e, tempDelay)
                time.Sleep(tempDelay)
                continue
            }
            return e
        }
        tempDelay = 0
        c, err := srv.newConn(rw)
        if err != nil {
            continue
        }
        go c.serve()
    }
}

http包核心之一 Conn

Go 为了实现高并发和高性能,使用了 goroutines 来处理 Conn 的读写事件,这样每个请求都能保持独立,相互不会阻塞,可以高效的响应网络事件。这是 Go 高效的保证

    c,err := srv.newConn(rw)

    if err != nil {
        continue
    }

    // 客户端的每次请求都会创建一个 Conn,这个 Conn 里面保存了该次请求的信息,
    // 然后再传递到对应的 handler,该 handler 中便可以读取到相应的 header 信息,
    // 这样保证了每个请求的独立性

    go c.serve()

http 包核心之二ServeMux

ServeMux 的自定义

其实内部是调用了 http 包默认的路由器,通过路由器把本次请求的信息传递到了后端的处理函数

type ServeMux struct {
    mu sync.RWMutex   // 锁,由于请求涉及到并发处理,因此这里需要一个锁机制
    m  map[string]muxEntry  // 路由规则,一个 string 对应一个 mux 实体,这里的 string 就是注册的路由表达式
    hosts bool // 是否在任意的规则中带有 host 信息
}

//muxEntry

type muxEntry struct {
    explicit bool   // 是否精确匹配
    h        Handler // 这个路由表达式对应哪个 handler
    pattern  string  // 匹配字符串
}

// Handler 的定义

type Handler interface {
    ServeHTTP(ResponseWriter, *Request)  // 路由实现器
}

自己实现一个简单的路由器


package main

import (
    "fmt"
    "net/http"
)

type MyMux struct {
}

func(p *MyMux) ServeHTTP(w http.ResponseWriter,r *http.Request) {
    if r.URL.Path == "/" {
        sayhelloName(w,r)
        return
    }

    http.NotFound(w,r)
    return
}

func sayhelloName(w http.ResponseWriter,r *http.Request) {
    fmt.Fprintf(w,"hello use myRoute")
}

func main(){
    mux := &MyMux{}

    http.ListenAndServe(":9527",mux)
}


Go Gin

Gin 是使用 Go/golang 语言实现的 HTTP Web 框架

Gin 有以下特性

- 快速:路由不使用反射,基于Radix树,内存占用少
- 中间件:HTTP请求,可先经过一系列中间件处理,例如:Logger,Authorization,GZIP等。这个特性和 NodeJs 的 Koa 框架很像。中间件机制也极大地提高了框架的可扩展性
- 异常处理:服务始终可用,不会宕机。Gin 可以捕获 panic,并恢复。而且有极为便利的机制处理HTTP请求过程中发生的错误.
- Gin可以解析并验证请求的JSON。这个特性对Restful API的开发尤其有用
- 路由分组:例如将需要授权和不需要授权的API分组,不同版本的API分组。而且分组可嵌套,且性能不受影响。
- 渲染内置:原生支持JSON,XML和HTML的渲染。

Example

package main

import "github.com/gin-gonic/gin"

func main() {
    // 首先,我们使用了gin.Default()生成了一个实例,这个实例即 WSGI 应用程序
    r := gin.Default()

    // 接下来,我们使用r.Get("/", ...)声明了一个路由,告诉 Gin 什么样的URL 能触发传入的函数,这个函数返回我们想要显示在用户浏览器中的信息
    r.GET('/',func(c *gin.Context){
        c.String(200,"hello ,world.")
    })

    // 最后用 r.Run()函数来让应用运行在本地服务器上,默认监听端口是 _8080_,可以传入参数设置端口,
    // 例如r.Run(":9999")即运行在 _9999_端口
    r.Run(":9527") // listen and serve on 0.0.0.0:9527
} 

运行: go run main.go


go-zero

go-zero 是一个集成了各种工程实践的web和rpc框架,通过弹性设计保障了大并发服务端的稳定性,经受了充分的实战检验。

- 轻松获得支撑千万日活服务的稳定性
- 内建级联超时控制、限流、自适应熔断、自适应降载等微服务治理能力,无需配置和额外代码
- 微服务治理中间件可无缝集成到其它现有框架使用
- 极简的API描述,一键生成各端代码
- 自动校验客户端请求参数合法性
- 大量微服务治理和并发工具包

Source Code