Golang請求fasthttp實(shí)踐
原計劃學(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()
}
}
測試報告
用的自帶的控制臺輸出內(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)文章
一文帶你深入了解Golang中的參數(shù)傳遞機(jī)制
值傳遞和引用傳遞是編程語言中兩種主要的參數(shù)傳遞方式,決定了函數(shù)調(diào)用過程中實(shí)參如何影響形參以及函數(shù)內(nèi)部對形參的修改是否會影響到原始實(shí)參,下面就跟隨小編一起深入了解下golang中參數(shù)傳遞機(jī)制吧2024-01-01
一文帶你學(xué)會Go?select語句輕松實(shí)現(xiàn)高效并發(fā)
這篇文章主要為大家詳細(xì)介紹了Golang中select語句的用法,文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)Golang有一定的幫助,需要的可以參考一下2023-03-03
Go結(jié)合反射將結(jié)構(gòu)體轉(zhuǎn)換成Excel的過程詳解
這篇文章主要介紹了Go結(jié)合反射將結(jié)構(gòu)體轉(zhuǎn)換成Excel的過程詳解,大概思路是在Go的結(jié)構(gòu)體中每個屬性打上一個excel標(biāo)簽,利用反射獲取標(biāo)簽中的內(nèi)容,作為表格的Header,需要的朋友可以參考下2022-06-06
golang獲取prometheus數(shù)據(jù)(prometheus/client_golang包)
本文主要介紹了使用Go語言的prometheus/client_golang包來獲取Prometheus監(jiān)控數(shù)據(jù),具有一定的參考價值,感興趣的可以了解一下2025-03-03
Go語言Gin框架中使用MySQL數(shù)據(jù)庫的三種方式
本文主要介紹了Go語言Gin框架中使用MySQL數(shù)據(jù)庫的三種方式,通過三種方式實(shí)現(xiàn)增刪改查的操作,具有一定的參考價值,感興趣的可以了解一下2023-11-11
Go語言學(xué)習(xí)函數(shù)+結(jié)構(gòu)體+方法+接口
這篇文章主要介紹了Go語言學(xué)習(xí)函數(shù)+結(jié)構(gòu)體+方法+接口,文章圍繞主題的相關(guān)資料展開詳細(xì)的文章說明,具有一定的參考價值,需要的小伙伴可以參考一下2022-05-05
解決vscode中g(shù)olang插件依賴安裝失敗問題
這篇文章主要介紹了解決vscode中g(shù)olang插件依賴安裝失敗問題,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下2019-08-08

