Boost Go HTTP Performance with fasthttp: Practical API Guide

This article explores the fasthttp library as a high‑performance alternative to Go's net/http client, demonstrates basic and advanced API usage with object pools, shows how to set up a mock test server, and provides complete Go unit‑test examples with output verification.

FunTester
FunTester
FunTester
Boost Go HTTP Performance with fasthttp: Practical API Guide

Why fasthttp?

After learning the standard net/http client, the author discovered github.com/valyala/fasthttp, which claims up to ten times the performance of net/http. The library achieves this partly by using two sync.Pool objects ( requestPool and responsePool) to reduce memory allocations during high‑throughput requests.

Basic API Demonstration

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) {
    // Fill form similar to 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)
    // Content‑type is optional for the server side
    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
}

FastGet and FastPostForm use the default request acquisition provided by fasthttp, while FastPostJson builds a custom request.

The call to req.Header.SetContentType is optional; most servers can parse the body regardless of the header.

High‑Performance API Demonstration (Object Pool)

package task

import (
    "crypto/tls"
    "encoding/json"
    "fmt"
    "github.com/valyala/fasthttp"
    "log"
    "time"
)

var FastClient fasthttp.Client = fastClient()

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
}

func FastPostJson(url string, args map[string]interface{}) *fasthttp.Request {
    req := fasthttp.AcquireRequest()
    req.Header.SetContentType("application/json")
    req.Header.SetMethod("POST")
    req.SetRequestURI(url)
    marshal, _ := json.Marshal(args)
    req.SetBody(marshal)
    return req
}

func FastPostForm(url string, args map[string]interface{}) *fasthttp.Request {
    req := fasthttp.AcquireRequest()
    req.Header.SetMethod("POST")
    req.SetRequestURI(url)
    marshal, _ := json.Marshal(args)
    req.BodyWriter().Write([]byte(ToValues(args)))
    req.BodyWriter().Write(marshal)
    return req
}

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("响应出错了")
        return nil, err
    }
    return response.Body(), nil
}

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
}

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,
    }
}

Test Service (Moco Framework)

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 = 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("恭喜到达QPS!"), 1))
        server.response("Have Fun ~ Tester !")
        def run = run(server)
        waitForKey("fan")
        run.stop()
    }
}

Go Unit Tests for the Wrapper

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() }
}

// Tests that use the original ft package directly
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() }
}

Test Report Output

=== 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
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

BackendperformanceGounit testingHTTP clientfasthttp
FunTester
Written by

FunTester

10k followers, 1k articles | completely useless

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.