Files
fasthttp/examples/client/client.go
T
2025-03-25 06:40:55 +01:00

133 lines
3.2 KiB
Go

package main
import (
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"os"
"reflect"
"time"
"github.com/valyala/fasthttp"
)
var headerContentTypeJSON = []byte("application/json")
var client *fasthttp.Client
type Entity struct {
Name string `json:"name"`
ID int `json:"id"`
}
func main() {
// You may read the timeouts from some config
readTimeout, _ := time.ParseDuration("500ms")
writeTimeout, _ := time.ParseDuration("500ms")
maxIdleConnDuration, _ := time.ParseDuration("1h")
client = &fasthttp.Client{
ReadTimeout: readTimeout,
WriteTimeout: writeTimeout,
MaxIdleConnDuration: maxIdleConnDuration,
NoDefaultUserAgentHeader: true, // Don't send: User-Agent: fasthttp
DisableHeaderNamesNormalizing: true, // If you set the case on your headers correctly you can enable this
DisablePathNormalizing: true,
// increase DNS cache time to an hour instead of default minute
Dial: (&fasthttp.TCPDialer{
Concurrency: 4096,
DNSCacheDuration: time.Hour,
}).Dial,
}
sendGetRequest()
sendPostRequest()
}
func sendGetRequest() {
req := fasthttp.AcquireRequest()
req.SetRequestURI("http://localhost:8080/")
req.Header.SetMethod(fasthttp.MethodGet)
resp := fasthttp.AcquireResponse()
err := client.Do(req, resp)
fasthttp.ReleaseRequest(req)
if err == nil {
fmt.Printf("DEBUG Response: %s\n", resp.Body())
} else {
fmt.Fprintf(os.Stderr, "ERR Connection error: %v\n", err)
}
fasthttp.ReleaseResponse(resp)
}
func sendPostRequest() {
// per-request timeout
reqTimeout := time.Duration(100) * time.Millisecond
reqEntity := &Entity{
Name: "New entity",
}
reqEntityBytes, _ := json.Marshal(reqEntity) //nolint:errchkjson
req := fasthttp.AcquireRequest()
req.SetRequestURI("http://localhost:8080/")
req.Header.SetMethod(fasthttp.MethodPost)
req.Header.SetContentTypeBytes(headerContentTypeJSON)
req.SetBodyRaw(reqEntityBytes)
resp := fasthttp.AcquireResponse()
err := client.DoTimeout(req, resp, reqTimeout)
fasthttp.ReleaseRequest(req)
defer fasthttp.ReleaseResponse(resp)
if err != nil {
errName, known := httpConnError(err)
if known {
fmt.Fprintf(os.Stderr, "WARN conn error: %v\n", errName)
} else {
fmt.Fprintf(os.Stderr, "ERR conn failure: %v %v\n", errName, err)
}
return
}
statusCode := resp.StatusCode()
respBody := resp.Body()
fmt.Printf("DEBUG Response: %s\n", respBody)
if statusCode != http.StatusOK {
fmt.Fprintf(os.Stderr, "ERR invalid HTTP response code: %d\n", statusCode)
return
}
respEntity := &Entity{}
err = json.Unmarshal(respBody, respEntity)
if err == nil || errors.Is(err, io.EOF) {
fmt.Printf("DEBUG Parsed Response: %v\n", respEntity)
} else {
fmt.Fprintf(os.Stderr, "ERR failed to parse response: %v\n", err)
}
}
func httpConnError(err error) (string, bool) {
var (
errName string
known = true
)
switch {
case errors.Is(err, fasthttp.ErrTimeout):
errName = "timeout"
case errors.Is(err, fasthttp.ErrNoFreeConns):
errName = "conn_limit"
case errors.Is(err, fasthttp.ErrConnectionClosed):
errName = "conn_close"
case reflect.TypeOf(err).String() == "*net.OpError":
errName = "timeout"
default:
known = false
}
return errName, known
}