TOC

fasthttp: 十倍速

https://github.com/valyala/fasthttp

fasthttp

package main

import (
    "flag"
    "fmt"
    "log"

    "github.com/valyala/fasthttp"
)

var (
    addr     = flag.String("addr", ":8080", "TCP address to listen to")
    compress = flag.Bool("compress", false, "Whether to enable transparent response compression")
)

func main() {
    flag.Parse()

    h := requestHandler
    if *compress {
        h = fasthttp.CompressHandler(h)
    }

    if err := fasthttp.ListenAndServe(*addr, h); err != nil {
        log.Fatalf("Error in ListenAndServe: %v", err)
    }
}

func requestHandler(ctx *fasthttp.RequestCtx) {
    fmt.Fprintf(ctx, "Hello, world!\n\n")

    fmt.Fprintf(ctx, "Request method is %q\n", ctx.Method())
    fmt.Fprintf(ctx, "RequestURI is %q\n", ctx.RequestURI())
    fmt.Fprintf(ctx, "Requested path is %q\n", ctx.Path())
    fmt.Fprintf(ctx, "Host is %q\n", ctx.Host())
    fmt.Fprintf(ctx, "Query string is %q\n", ctx.QueryArgs())
    fmt.Fprintf(ctx, "User-Agent is %q\n", ctx.UserAgent())
    fmt.Fprintf(ctx, "Connection has been established at %s\n", ctx.ConnTime())
    fmt.Fprintf(ctx, "Request has been started at %s\n", ctx.Time())
    fmt.Fprintf(ctx, "Serial request number for the current connection is %d\n", ctx.ConnRequestNum())
    fmt.Fprintf(ctx, "Your ip is %q\n\n", ctx.RemoteIP())

    fmt.Fprintf(ctx, "Raw request is:\n---CUT---\n%s\n---CUT---", &ctx.Request)

    ctx.SetContentType("text/plain; charset=utf8")

    // Set arbitrary headers
    ctx.Response.Header.Set("X-My-Header", "my-header-value")

    // Set cookies
    var c fasthttp.Cookie
    c.SetKey("cookie-name")
    c.SetValue("cookie-value")
    ctx.Response.Header.SetCookie(&c)
}
  • r.Body -> ctx.PostBody()
  • r.URL.Path -> ctx.Path()
  • r.URL -> ctx.URI()
  • r.Method -> ctx.Method()
  • r.Header -> ctx.Request.Header
  • r.Header.Get() -> ctx.Request.Header.Peek()
  • r.Host -> ctx.Host()
  • r.Form -> ctx.QueryArgs() + ctx.PostArgs()
  • r.PostForm -> ctx.PostArgs()
  • r.FormValue() -> ctx.FormValue()
  • r.FormFile() -> ctx.FormFile()
  • r.MultipartForm -> ctx.MultipartForm()
  • r.RemoteAddr -> ctx.RemoteAddr()
  • r.RequestURI -> ctx.RequestURI()
  • r.TLS -> ctx.IsTLS()
  • r.Cookie() -> ctx.Request.Header.Cookie()
  • r.Referer() -> ctx.Referer()
  • r.UserAgent() -> ctx.UserAgent()
  • w.Header() -> ctx.Response.Header
  • w.Header().Set() -> ctx.Response.Header.Set()
  • w.Header().Set("Content-Type") -> ctx.SetContentType()
  • w.Header().Set("Set-Cookie") -> ctx.Response.Header.SetCookie()
  • w.Write() -> ctx.Write(), ctx.SetBody(), ctx.SetBodyStream(), ctx.SetBodyStreamWriter()
  • w.WriteHeader() -> ctx.SetStatusCode()
  • w.(http.Hijacker).Hijack() -> ctx.Hijack()
  • http.Error() -> ctx.Error()
  • http.FileServer() -> fasthttp.FSHandler(), fasthttp.FS
  • http.ServeFile() -> fasthttp.ServeFile()
  • http.Redirect() -> ctx.Redirect()
  • http.NotFound() -> ctx.NotFound()
  • http.StripPrefix() -> fasthttp.PathRewriteFunc

fasthttp/router

  • /user/{user} named
  • /user/{user}_admin
  • /user/{user?} optional
  • /user/{name:[a-zA-Z]{5}} regex
  • /user/{name?:[a-zA-Z]{5}}
  • /user/{name:*} cache all

fasthttp/session

package main

import (
    "log"
    "time"

    "github.com/fasthttp/session/v2"
    "github.com/fasthttp/session/v2/providers/redis"
)

var serverSession *session.Session

func init() {
    var provider session.Provider
    var err error
    encoder := session.MSGPEncode
    decoder := session.MSGPDecode
    provider, err = redis.New(redis.Config{
        KeyPrefix:   "session",
        Addr:        "127.0.0.1:6379",
        PoolSize:    8,
        IdleTimeout: 30 * time.Second,
    })
    if err != nil {
        log.Fatal(err)
    }
    cfg := session.NewDefaultConfig()
    cfg.EncodeFunc = encoder
    cfg.DecodeFunc = decoder
    serverSession = session.New(cfg)
    if err = serverSession.SetProvider(provider); err != nil {
        log.Fatal(err)
    }
}
// 获取 SessionStore
store, err := serverSession.Get(ctx)
if err != nil {
    ctx.Error(err.Error(), fasthttp.StatusInternalServerError)
    return
}
defer func() {
    if err := serverSession.Save(ctx, store); err != nil {
        ctx.Error(err.Error(), fasthttp.StatusInternalServerError)
    }
}()

// Set
store.Set("foo", "bar")

// Get
val := store.Get("foo")
if val == nil {
    // ...
}

store.Delete(key)

store.Set(bytesKey)
val := store.GetBytes(bytesKey)
store.DeleteBytes(bytesKey)

data := store.GetAll()  // Dict
data := store.Ptr()     // *Dict

store.Flush()
store.Reset()

// Session ID,默认 sessionid
id := store.GetSessionID()
store.SetSessionID(bytesID)

// Session 有效期
changed := store.HasExpirationChanged()
duration := store.GetExpiration()
err := store.SetExpiration(duration)

savsgio/atreugo

构建与 fasthttp 和 fasthttp/router 之上的 HTTP 框架,做了一些简单的封装工作。
提供了几个示例

基础用法:

package main

import (
    "github.com/savsgio/atreugo/v11"
)

func main() {
    config := atreugo.Config{
        Addr: "0.0.0.0:8000",
    }
    server := atreugo.New(config)

    server.GET("/", func(ctx *atreugo.RequestCtx) error {
        return ctx.TextResponse("Hello World")
    })

    server.GET("/echo/{path:*}", func(ctx *atreugo.RequestCtx) error {
        return ctx.TextResponse("Echo message: " + ctx.UserValue("path").(string))
    })

    v1 := server.NewGroupPath("/v1")
    v1.GET("/", func(ctx *atreugo.RequestCtx) error {
        return ctx.TextResponse("Hello V1 Group")
    })

    if err := server.ListenAndServe(); err != nil {
        panic(err)
    }
}