- 2021/04/26, fasthttp: 十倍速
- 2023/06/27, fasthttp 与 fiber 框架
- 2024/01/28, Fasthttp
代码结构
https://github.com/valyala/fasthttp/tree/v1.51.0
https://github.com/valyala/fasthttp/archive/refs/tags/v1.51.0.zip
module github.com/valyala/fasthttp
go 1.20
require (
github.com/andybalholm/brotli v1.0.5
github.com/klauspost/compress v1.17.0
github.com/valyala/bytebufferpool v1.0.0
github.com/valyala/tcplisten v1.0.0
golang.org/x/crypto v0.14.0
golang.org/x/net v0.17.0
golang.org/x/sys v0.13.0
)
require golang.org/x/text v0.13.0 // indirect
$ tree .
.
├── allocation_test.go
├── args.go
├── args_test.go
├── args_timing_test.go
├── b2s_new.go
├── b2s_old.go
├── brotli.go
├── brotli_test.go
├── bytesconv.go
├── bytesconv_32.go
├── bytesconv_32_test.go
├── bytesconv_64.go
├── bytesconv_64_test.go
├── bytesconv_table.go
├── bytesconv_table_gen.go
├── bytesconv_test.go
├── bytesconv_timing_test.go
├── client.go
├── client_example_test.go
├── client_test.go
├── client_timing_test.go
├── client_timing_wait_test.go
├── client_unix_test.go
├── coarsetime.go
├── coarsetime_test.go
├── compress.go
├── compress_test.go
├── cookie.go
├── cookie_test.go
├── cookie_timing_test.go
├── doc.go
├── examples
│ ├── client
│ │ ├── client.go
│ │ ├── Makefile
│ │ └── README.md
│ ├── fileserver
│ │ ├── fileserver.go
│ │ ├── Makefile
│ │ ├── README.md
│ │ ├── ssl-cert-snakeoil.key
│ │ └── ssl-cert-snakeoil.pem
│ ├── helloworldserver
│ │ ├── helloworldserver.go
│ │ ├── Makefile
│ │ └── README.md
│ ├── host_client
│ │ ├── hostclient.go
│ │ ├── Makefile
│ │ └── README.md
│ ├── letsencrypt
│ │ └── letsencryptserver.go
│ ├── multidomain
│ │ ├── Makefile
│ │ ├── multidomain.go
│ │ └── README.md
│ └── README.md
├── expvarhandler
│ ├── expvar.go
│ └── expvar_test.go
├── fasthttpadaptor
│ ├── adaptor.go
│ ├── adaptor_test.go
│ ├── b2s_new.go
│ ├── b2s_old.go
│ ├── request.go
│ └── request_test.go
├── fasthttpproxy
│ ├── http.go
│ ├── proxy_env.go
│ └── socks5.go
├── fasthttputil
│ ├── doc.go
│ ├── inmemory_listener.go
│ ├── inmemory_listener_test.go
│ ├── inmemory_listener_timing_test.go
│ ├── pipeconns.go
│ └── pipeconns_test.go
├── fs.go
├── fs_example_test.go
├── fs_fs_test.go
├── fs_handler_example_test.go
├── fs_test.go
├── fuzzit
│ ├── cookie
│ │ └── cookie_fuzz.go
│ ├── request
│ │ └── request_fuzz.go
│ ├── response
│ │ └── response_fuzz.go
│ └── url
│ └── url_fuzz.go
├── go.mod
├── go.sum
├── header.go
├── header_regression_test.go
├── header_test.go
├── header_timing_test.go
├── headers.go
├── http.go
├── http_test.go
├── lbclient.go
├── lbclient_example_test.go
├── LICENSE
├── methods.go
├── nocopy.go
├── peripconn.go
├── peripconn_test.go
├── pprofhandler
│ └── pprof.go
├── prefork
│ ├── prefork.go
│ ├── prefork_test.go
│ └── README.md
├── README.md
├── requestctx_setbodystreamwriter_example_test.go
├── reuseport
│ ├── LICENSE
│ ├── reuseport.go
│ ├── reuseport_aix.go
│ ├── reuseport_error.go
│ ├── reuseport_example_test.go
│ ├── reuseport_test.go
│ └── reuseport_windows.go
├── round2_32.go
├── round2_32_test.go
├── round2_64.go
├── round2_64_test.go
├── s2b_new.go
├── s2b_old.go
├── SECURITY.md
├── server.go
├── server_example_test.go
├── server_test.go
├── server_timing_test.go
├── stackless
│ ├── doc.go
│ ├── func.go
│ ├── func_test.go
│ ├── func_timing_test.go
│ ├── writer.go
│ └── writer_test.go
├── status.go
├── status_test.go
├── status_timing_test.go
├── stream.go
├── stream_test.go
├── stream_timing_test.go
├── streaming.go
├── streaming_test.go
├── strings.go
├── tcp.go
├── tcp_windows.go
├── tcpdialer.go
├── testdata
│ └── test.png
├── timer.go
├── tls.go
├── TODO
├── uri.go
├── uri_test.go
├── uri_timing_test.go
├── uri_unix.go
├── uri_windows.go
├── uri_windows_test.go
├── userdata.go
├── userdata_test.go
├── userdata_timing_test.go
├── workerpool.go
└── workerpool_test.go
21 directories, 149 files
Request / Response
type RequestCtx struct {
noCopy noCopy
Request Request
Response Response
userValues userData
connID uint64
connRequestNum uint64
connTime time.Time
remoteAddr net.Addr
time time.Time
logger ctxLogger
s *Server
c net.Conn
fbr firstByteReader
timeoutResponse *Response
timeoutCh chan struct{}
timeoutTimer *time.Timer
hijackHandler HijackHandler
hijackNoResponse bool
formValueFunc FormValueFunc
}
type Request struct {
noCopy noCopy
Header RequestHeader
uri URI
postArgs Args
bodyStream io.Reader
w requestBodyWriter
body *bytebufferpool.ByteBuffer
bodyRaw []byte
multipartForm *multipart.Form
multipartFormBoundary string
secureErrorLogMessage bool
parsedURI bool
parsedPostArgs bool
keepBodyBuffer bool
isTLS bool
timeout time.Duration
UseHostHeader bool
DisableRedirectPathNormalizing bool
}
type RequestHeader struct {
noCopy noCopy
disableNormalizing bool
noHTTP11 bool
connectionClose bool
noDefaultContentType bool
disableSpecialHeader bool
cookiesCollected bool
contentLength int
contentLengthBytes []byte
secureErrorLogMessage bool
method []byte
requestURI []byte
proto []byte
host []byte
contentType []byte
userAgent []byte
mulHeader [][]byte
h []argsKV
trailer []argsKV
bufKV argsKV
cookies []argsKV
rawHeaders []byte
}
type Response struct {
noCopy noCopy
Header ResponseHeader
ImmediateHeaderFlush bool
StreamBody bool
bodyStream io.Reader
w responseBodyWriter
body *bytebufferpool.ByteBuffer
bodyRaw []byte
SkipBody bool
keepBodyBuffer bool
secureErrorLogMessage bool
raddr net.Addr
laddr net.Addr
}
func requestHandler(ctx *fasthttp.RequestCtx) {
// 获取 URL 参数
queryArgs := ctx.QueryArgs()
queryArgs.VisitAll(func(key, value []byte) {
fmt.Printf("URL(querystring) %s: %s\n", key, value)
})
name := queryArgs.GetString("name", "default_value")
fmt.Printf("name: %s\n", name)
// 获取所有请求头
ctx.Request.Header.VisitAll(func(key, value []byte) {
fmt.Printf("Header %s: %s\n", key, value)
})
// 获取 Body 参数(表单参数)
if ctx.IsPost() || ctx.IsPut() {
fmt.Println("Form Parameters:")
formArgs := ctx.FormArgs()
formArgs.VisitAll(func(key, value []byte) {
fmt.Printf(" %s: %s\n", key, value)
})
}
// 获取 JSON 请求体中的参数(如果存在 JSON)
if strings.Contains(string(ctx.Request.Header.ContentType()), "application/json") {
var jsonBody map[string]interface{}
if err := json.Unmarshal(ctx.Request.Body(), &jsonBody); err != nil {
fmt.Println("Failed to parse JSON body:", err)
} else {
fmt.Println("JSON Body Parameters:")
for key, value := range jsonBody {
fmt.Printf(" %s: %v\n", key, value)
}
}
}
}
// 封装获取客户端 IP 地址的逻辑
func getRemoteAddr(ctx *fasthttp.RequestCtx) string {
// 首先检查 X-Forwarded-For 头部是否存在
xForwardedFor := string(ctx.Request.Header.Peek("X-Forwarded-For"))
if xForwardedFor != "" {
// X-Forwarded-For 头部包含一个以逗号分隔的 IP 地址列表,取第一个(客户端真实 IP)
clientIP := strings.Split(xForwardedFor, ",")[0]
return clientIP
}
// 如果没有 X-Forwarded-For 头,则返回 RequestCtx 的 RemoteAddr(包含 IP 和端口)
return ctx.RemoteAddr().String()
}
RequestHeader
通过复用 slice 来提升效率。
type Args struct {
noCopy noCopy
args []argsKV
buf []byte
}
type argsKV struct {
key []byte
value []byte
noValue bool
}
func (a *Args) Add(key, value string) {
a.args = appendArg(a.args, key, value, argsHasValue)
}
func appendArg(args []argsKV, key, value string, noValue bool) []argsKV {
var kv *argsKV
args, kv = allocArg(args)
kv.key = append(kv.key[:0], key...)
if noValue {
kv.value = kv.value[:0]
} else {
kv.value = append(kv.value[:0], value...)
}
kv.noValue = noValue
return args
}
func allocArg(h []argsKV) ([]argsKV, *argsKV) {
n := len(h)
if cap(h) > n {
h = h[:n+1]
} else {
h = append(h, argsKV{
value: []byte{},
})
}
return h, &h[n]
}
func (a *Args) Reset() {
a.args = a.args[:0]
}