fasthttp 高性能第三方http包

简介

fasthttp 据说是目前golang性能最好的http库,相对于自带的net/http,性能说是有10倍的提升,具体介绍可以看看官方介绍: valyala/fasthttp

正好最近需要用到,但是发现网上的资料也不是很多,特别是关于client模块的就更少了,只有一些翻译成中文的文档,于是乎就把关于client的代码研究了一下,总结了一些比较简单的使用方法,测试对比net/http是有一定程度的提升,如果需要用到http client似乎fasthttp也是一个不错的选择,当然fasthttp也可以用来做http服务的,不过着并不在此次研究范围内。

顺便也提下他的不足之处吧: 一个是他目前还没有支持http2, 一个是不支持WebSocket,但是WebSocket貌似已经有第三方库的支持了。

fasthttp截至目前为止的todo list:

文档连接

api文档:https://godoc.org/github.com/valyala/fasthttp#RequestCtx

一、简单例子

照例先来一个简单例子:

import (
	"fmt"

	"github.com/valyala/fasthttp"
)
//相应请求的函数 RequestCtx 传递数据
func testhandle(ctx *fasthttp.RequestCtx) {
	fmt.Fprintf(ctx, "hello world")
}

func main() {
	if err := fasthttp.ListenAndServe(":8001", testhandle); err != nil {
		fmt.Println("start fasthttp fail", err.Error())
	}
}

浏览器访问 http://127.0.0.1:8001/ 就可以看到hello world

二、路由

net/http 提供 http.ServeMux 实现路由服务,但是匹配规则简陋,功能很简单,基本不会使用。fasthttp 吸取教训,默认没有提供路由支持。因此使用第三方的 fasthttp 的路由库 fasthttprouter 来辅助路由实现:

import (
	"fmt"

	"github.com/buaazp/fasthttprouter"
	"github.com/valyala/fasthttp"
)
//路由函数没有变,可以通过UserValue方法获取路由路径
func testhandle(ctx *fasthttp.RequestCtx) {
	fmt.Fprintf(ctx, "hello world--> %s!\n", ctx.UserValue("name"))
}

func main() {
	router := fasthttprouter.New()
	//“/:name”为url中的匹配字符名称,与UserValue函数内的参数对应
	router.GET("/:name", testhandle)
	if err := fasthttp.ListenAndServe(":8001", router.Handler); err != nil {
		fmt.Println("start fasthttp fail", err.Error())
	}
}

三、获取请求信息

*RequestCtx 综合 http.Request 和 http.ResponseWriter 的操作,可以更方便的读取和返回数据。
将相应函数改为:

func texthandle(ctx *fasthttp.RequestCtx) {
	ctx.SetContentType("text/html") // 记得添加 Content-Type:text/html,否则都当纯文本返回
	fmt.Fprintf(ctx, "Method:%s <br/>", ctx.Method())
	fmt.Fprintf(ctx, "URI:%s <br/>", ctx.URI())
	fmt.Fprintf(ctx, "RemoteAddr:%s <br/>", ctx.RemoteAddr())
	fmt.Fprintf(ctx, "UserAgent:%s <br/>", ctx.UserAgent())
	fmt.Fprintf(ctx, "Header.Accept:%s <br/>", ctx.Request.Header.Peek("Accept"))
}

请求当前服务,返回如下图
在这里插入图片描述
当然还有更多的信息,如下,不等

	fmt.Fprintf(ctx, "IP:%s <br/>", ctx.RemoteIP())
	fmt.Fprintf(ctx, "Host:%s <br/>", ctx.Host())
	fmt.Fprintf(ctx, "ConnectTime:%s <br/>", ctx.ConnTime()) // 连接收到处理的时间
	fmt.Fprintf(ctx, "IsGET:%v <br/>", ctx.IsGet())          // 类似有 IsPOST, IsPUT 等

四、获取数据

我忽略了很多错误处理,在实际使用中,千万千万要处理掉错误。

获取url参数

	fmt.Println(string(ctx.PostBody())) //打印请求体
	//ctx.Request.BodyGunzip()  获取Gzip个数数据
	getpost := ctx.QueryArgs()
	// 127.0.0.1:8001/text?aaa=123&aaa=haha
	fmt.Fprintf(ctx, "post aaa first = %s <br/>", getpost.Peek("aaa"))                             //只获取第一个值
	fmt.Fprintf(ctx, "post aaa all = %s <br/>", bytes.Join(getpost.PeekMulti("aaa"), []byte(","))) //获取全部

获取表单参数

	getform := ctx.FormValue("aaa")
	fmt.Fprintf(ctx, "form aaa = %s", getform)

文件操作

	getform, _ := ctx.FormFile("aaa")
	file, _ := getform.Open()
	defer file.Close()
	ctx.SetContentType("image/jpeg")
	filel, _ := os.OpenFile("./haha.jpg", os.O_CREATE|os.O_WRONLY, 0644)
	defer filel.Close()
	io.Copy(filel, file)

五、返回内容

错误标志,字符串 推送

	ctx.WriteString("hello,fasthttp")
	// 因为实现不同,fasthttp 的返回内容不是即刻返回的
	// 不同于标准库,添加返回内容后设置状态码,也是有效的
	ctx.SetStatusCode(404)

	// 返回的内容也是可以获取的,不需要标准库的用法,需要自己扩展 http.ResponseWriter
	fmt.Println(string(ctx.Response.Body()))

文件推送

func httpHandle(ctx *fasthttp.RequestCtx) {
	ctx.SendFile("abc.txt")
}

六、RequestCtx 复用

不推荐RequestCtx 复用

七、限流器

Rate Limiter 限流器
限流器模块提供了到限流器代码包的端点适配器。限流器对服务端和客户端同等生效,使用限流器可以强制进、出请求量在阈值以下。使用限流器能限制访问后端的流量,起到一个保护作用,被限制的流量,可以根据具体的业务逻辑去处理,直接返回错误或者返回默认值。
go-kit的限流器模块是封装了golang自带的golang.org/x/time/rate包来实现的,提供了两种限流:

  • DelayingLimiter【限流延迟访问】,
  • ErroringLimiter【限流错误返回】。
    看源码
// NewDelayingLimiter是go-kit实现的ratelimiter,我们可以直接使用。
func NewDelayingLimiter(limit ratelimit.Waiter) endpoint.Middleware {
   return func(next endpoint.Endpoint) endpoint.Endpoint {
      return func(ctx context.Context, request interface{}) (interface{}, error) {
         if err := limit.Wait(ctx); err != nil {
            return nil, err
         }
         return next(ctx, request)
      }
   }
}

使用也很简单,下面看代码

// 如何使用此中间件
import (
	"golang.org/x/time/rate"
	"github.com/go-kit/kit/ratelimit"
)
limiter := rate.NewLimiter(rate.Every(time.Second * 1), 1) 
GetSpecEndpoint = ratelimit.NewDelayingLimiter(limiter)(GetSpecEndpoint) 
getSpecHandler := httptransport.NewServer(
	GetSpecEndpoint,
	decodes.GetSpecDecode,
	encodes.GetSpecEncode,
)

未完待续。。。

发布了53 篇原创文章 · 获赞 5 · 访问量 2314

猜你喜欢

转载自blog.csdn.net/qq_25490573/article/details/104014620