Golang請求fasthttp實(shí)踐
原計(jì)劃學(xué)完Golang語言HTTP客戶端實(shí)踐之后,就可以繼續(xù)了,沒想到才疏學(xué)淺,在搜資料的時候發(fā)現(xiàn)除了Golang SDK自帶的net/http,還有一個更牛的HttpClient實(shí)現(xiàn)github.com/valyala/fasthttp,據(jù)說性能是net/http的10倍,我想可能是有點(diǎn)夸張了,后期我會進(jìn)行測試,以正視聽。
在github.com/valyala/fasthttp用到了對象池,為了在高性能測試中減少內(nèi)存的使用,fasthttp使用了兩個對象池(我只看了這倆):requestPool sync.Pool和responsePool sync.Pool,當(dāng)然fasthttp也提供了正常的對象創(chuàng)建API,后面我在案例中也會寫到。
基礎(chǔ)API演示
首先分享一下基礎(chǔ)的用法封裝:
PS:這個屬于練習(xí)版本,所以沒寫多少注釋。
package ft import ( "encoding/json" "fmt" "funtester/task" "github.com/valyala/fasthttp" ) func FastGet(url string, args map[string]interface{}) ([]byte, error) { uri := url + "?" + task.ToValues(args) _, resp, err := fasthttp.Get(nil, uri) if err != nil { fmt.Println("請求失敗:", err.Error()) return nil, err } return resp, err } func FastPostForm(url string, args map[string]interface{}) ([]byte, error) { // 填充表單,類似于net/url params := &fasthttp.Args{} for s, i2 := range args { sprintf := fmt.Sprintf("%v", i2) params.Add(s, sprintf) } _, resp, err := fasthttp.Post(nil, url, params) if err != nil { fmt.Println("請求失敗:", err.Error()) return nil, err } return resp, nil } func FastPostJson(url string, args map[string]interface{}) ([]byte, error) { req := &fasthttp.Request{} req.SetRequestURI(url) marshal, _ := json.Marshal(args) req.SetBody(marshal) // 默認(rèn)是application/x-www-form-urlencoded,其實(shí)無所謂 req.Header.SetContentType("application/json") req.Header.SetMethod("POST") resp := &fasthttp.Response{} if err := fasthttp.Do(req, resp); err != nil { fmt.Println("請求失敗:", err.Error()) return nil, err } return resp.Body(), nil }
其中兩點(diǎn)主要注意:
- FastGet、FastPostForm使用的fasthttp提供的默認(rèn)獲取請求的方式,F(xiàn)astPostJson使用了自定義請求和獲取響應(yīng)的方式
- 關(guān)于請求頭中的req.Header.SetContentType方法,其實(shí)無所謂,服務(wù)端都可以解析
高性能API演示
下面分享使用更高的性能(基于對象池)的API創(chuàng)建請求和獲取響應(yīng)的方式:
package task import ( "crypto/tls" "encoding/json" "fmt" "github.com/valyala/fasthttp" "log" "time" ) var FastClient fasthttp.Client = fastClient() // FastGet 獲取GET請求對象,沒有進(jìn)行資源回收 // @Description: // @param url // @param args // @return *fasthttp.Request func FastGet(url string, args map[string]interface{}) *fasthttp.Request { req := fasthttp.AcquireRequest() req.Header.SetMethod("GET") values := ToValues(args) req.SetRequestURI(url + "?" + values) return req } // FastPostJson POST請求JSON參數(shù),沒有進(jìn)行資源回收 // @Description: // @param url // @param args // @return *fasthttp.Request func FastPostJson(url string, args map[string]interface{}) *fasthttp.Request { req := fasthttp.AcquireRequest() // 默認(rèn)是application/x-www-form-urlencoded req.Header.SetContentType("application/json") req.Header.SetMethod("POST") req.SetRequestURI(url) marshal, _ := json.Marshal(args) req.SetBody(marshal) return req } // FastPostForm POST請求表單傳參,沒有進(jìn)行資源回收 // @Description: // @param url // @param args // @return *fasthttp.Request func FastPostForm(url string, args map[string]interface{}) *fasthttp.Request { req := fasthttp.AcquireRequest() // 默認(rèn)是application/x-www-form-urlencoded //req.Header.SetContentType("application/json") req.Header.SetMethod("POST") req.SetRequestURI(url) marshal, _ := json.Marshal(args) req.BodyWriter().Write([]byte(ToValues(args))) req.BodyWriter().Write(marshal) return req } // FastResponse 獲取響應(yīng),保證資源回收 // @Description: // @param request // @return []byte // @return error func FastResponse(request *fasthttp.Request) ([]byte, error) { response := fasthttp.AcquireResponse() defer fasthttp.ReleaseResponse(response) defer fasthttp.ReleaseRequest(request) if err := FastClient.Do(request, response); err != nil { log.Println("響應(yīng)出錯了") return nil, err } return response.Body(), nil } // DoGet 發(fā)送GET請求,獲取響應(yīng) // @Description: // @param url // @param args // @return []byte // @return error func DoGet(url string, args map[string]interface{}) ([]byte, error) { req := fasthttp.AcquireRequest() defer fasthttp.ReleaseRequest(req) // 用完需要釋放資源 req.Header.SetMethod("GET") values := ToValues(args) req.SetRequestURI(url + "?" + values) resp := fasthttp.AcquireResponse() defer fasthttp.ReleaseResponse(resp) // 用完需要釋放資源 if err := FastClient.Do(req, resp); err != nil { fmt.Println("請求失敗:", err.Error()) return nil, err } return resp.Body(), nil } // fastClient 獲取fast客戶端 // @Description: // @return fasthttp.Client func fastClient() fasthttp.Client { return fasthttp.Client{ Name: "FunTester", NoDefaultUserAgentHeader: true, TLSConfig: &tls.Config{InsecureSkipVerify: true}, MaxConnsPerHost: 2000, MaxIdleConnDuration: 5 * time.Second, MaxConnDuration: 5 * time.Second, ReadTimeout: 5 * time.Second, WriteTimeout: 5 * time.Second, MaxConnWaitTimeout: 5 * time.Second, } }
測試服務(wù)
用的還是moco_FunTester測試框架,腳本如下:
package com.mocofun.moco.main import com.funtester.utils.ArgsUtil import com.mocofun.moco.MocoServer import org.apache.tools.ant.taskdefs.condition.And class Share extends MocoServer { static void main(String[] args) { def util = new ArgsUtil(args) // def server = getServerNoLog(util.getIntOrdefault(0,12345)) def server = getServer(util.getIntOrdefault(0, 12345)) server.get(both(urlStartsWith("/test"),existArgs("code"))).response("get請求") server.post(both(urlStartsWith("/test"), existForm("fun"))).response("post請求form表單") server.post(both(urlStartsWith("/test"), existParams("fun"))).response("post請求json表單") server.get(urlStartsWith("/qps")).response(qps(textRes("恭喜到達(dá)QPS!"), 1)) // server.response(delay(jsonRes(getJson("Have=Fun ~ Tester !")), 1000)) server.response("Have Fun ~ Tester !") def run = run(server) waitForKey("fan") run.stop() } }
Golang單元測試
第一次寫Golang單測,有點(diǎn)不適應(yīng),搞了很久才通。
package test import ( "funtester/ft" "funtester/task" "log" "testing" ) const url = "http://localhost:12345/test" func args() map[string]interface{} { return map[string]interface{}{ "code": 32, "fun": 32, "msg": "324", } } func TestGet(t *testing.T) { get := task.FastGet(url, args()) res, err := task.FastResponse(get) if err != nil { t.Fail() } v := string(res) log.Println(v) if v != "get請求" { t.Fail() } } func TestPostJson(t *testing.T) { post := task.FastPostJson(url, args()) res, err := task.FastResponse(post) if err != nil { t.Fail() } v := string(res) log.Println(v) if v != "post請求json表單" { t.Fail() } } func TestPostForm(t *testing.T) { post := task.FastPostForm(url, args()) res, err := task.FastResponse(post) if err != nil { t.Fail() } v := string(res) log.Println(v) if v != "post請求form表單" { t.Fail() } } func TestGetNor(t *testing.T) { res, err := ft.FastGet(url, args()) if err != nil { t.Fail() } v := string(res) log.Println(v) if v != "get請求" { t.Fail() } } func TestPostJsonNor(t *testing.T) { res, err := ft.FastPostJson(url, args()) if err != nil { t.Fail() } v := string(res) log.Println(v) if v != "post請求json表單" { t.Fail() } } func TestPostFormNor(t *testing.T) { res, err := ft.FastPostForm(url, args()) if err != nil { t.Fail() } v := string(res) log.Println(v) if v != "post請求form表單" { t.Fail() } }
測試報(bào)告
用的自帶的控制臺輸出內(nèi)容:
=== RUN TestGet
2021/10/18 18:56:49 get請求
--- PASS: TestGet (0.01s)
=== RUN TestPostJson
2021/10/18 18:56:49 post請求json表單
--- PASS: TestPostJson (0.00s)
=== RUN TestPostForm
2021/10/18 18:56:49 post請求form表單
--- PASS: TestPostForm (0.00s)
=== RUN TestGetNor
2021/10/18 18:56:49 get請求
--- PASS: TestGetNor (0.00s)
=== RUN TestPostJsonNor
2021/10/18 18:56:49 post請求json表單
--- PASS: TestPostJsonNor (0.00s)
=== RUN TestPostFormNor
2021/10/18 18:56:49 post請求form表單
--- PASS: TestPostFormNor (0.00s)
=== RUN TestStageJSON
到此這篇關(guān)于Golang請求fasthttp實(shí)踐的文章就介紹到這了,更多相關(guān)Golang請求fasthttp內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Go語言里的結(jié)構(gòu)體文法實(shí)例分析
這篇文章主要介紹了Go語言里的結(jié)構(gòu)體文法,實(shí)例分析了結(jié)構(gòu)體文法的概念及使用技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-02-02Go語言的Windows下環(huán)境配置以及簡單的程序結(jié)構(gòu)講解
這篇文章主要介紹了Go語言的Windows下環(huán)境配置以及簡單的程序結(jié)構(gòu)講解,從編程語言約定俗成的hellow world開始,需要的朋友可以參考下2015-10-10Go gin權(quán)限驗(yàn)證實(shí)現(xiàn)過程詳解
這篇文章主要為大家介紹了Go gin權(quán)限驗(yàn)證實(shí)現(xiàn)過程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01Golang優(yōu)雅關(guān)閉channel的方法示例
Goroutine和channel是Go在“并發(fā)”方面兩個核心feature,下面這篇文章主要給大家介紹了關(guān)于Golang如何優(yōu)雅關(guān)閉channel的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考解決,下面來一起看看吧。2017-11-11如何在golang中使用shopspring/decimal來處理精度問題
本文主要介紹了如何在golang中使用shopspring/decimal來處理精度問題,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-04-04Golang使用gzip壓縮字符減少redis等存儲占用的實(shí)現(xiàn)
本文主要介紹了Golang使用gzip壓縮字符減少redis等存儲占用的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-01-01