Go 高性能库 fasthttp 完整使用指南

什么是 Fasthttp

fasthttp 是 Go 语言生态中性能极致的 HTTP 服务器 / 客户端库,专为高并发、低延迟场景设计(如网关、微服务、压测工具、高 QPS 接口服务)。

  • 官方定位:比 Go 标准库 net/http 快 10 倍以上,内存分配极少
  • 核心优势:零 / 低内存分配、连接复用、对象池化、原生支持 HTTP/1.1 全特性
  • 适用场景:高并发 API 服务、反向代理、网关、压测客户端
  • 不适用场景:需要 HTTP/2、HTTP/3、WebSocket 完整扩展(fasthttp 对 WebSocket 支持有限)

Fasthttp 核心原理(为什么这么快?)

fasthttp 的高性能完全围绕减少内存分配、避免 GC、复用资源设计,核心原理如下:

  1. sync.Pool 对象池化(核心)
  • 标准库 net/http 每次请求都会新建 Request/Response 对象,GC 压力极大
  • fasthttp 用 sync.Pool 缓存所有高频对象(Request、Response、Ctx、Buffer),请求结束后重置对象并放回池内复用,几乎零内存分配
  1. 减少系统调用与拷贝
  • 原生使用零拷贝技术处理请求体 / 响应体
  • 避免 \[\]byte 和 string 频繁转换(fasthttp 大量使用 \[\]byte 处理数据,比 string 更快)
  1. 连接复用与长连接
  • 默认强制开启 HTTP/1.1 长连接,减少 TCP 握手 / 挥手开销
  • 优化了 TCP 读写缓冲区,高并发下连接数大幅降低
  1. 精简的请求上下文
  • 用 *fasthttp.RequestCtx 替代标准库的 http.ResponseWriter + *http.Request
  • 所有方法直接操作字节,无反射、无多余封装,单请求处理耗时极低
  1. 高性能路由
  • 基于前缀树实现路由匹配,比正则路由快一个数量级
  • 支持静态路由、参数路由、通配符路由

环境安装

go 复制代码
go get github.com/valyala/fasthttp

Fasthttp 完整 API 分类 + 实战示例

按照服务器、客户端、请求 / 响应操作、路由、工具函数五大类,覆盖几乎所有核心 API,每个 API 都配可直接运行的示例

第一部分:FastHTTP 服务器核心 API

ListenAndServe(addr string, handler RequestHandler) error

作用:启动 HTTP 服务器(最基础 API),监听指定地址

go 复制代码
package main

import (
	"github.com/valyala/fasthttp"
)

// 处理器函数:所有请求都会进入这里
func requestHandler(ctx *fasthttp.RequestCtx) {
	// 响应文本
	ctx.WriteString("Hello Fasthttp!")
}

func main() {
	// 启动服务器:监听 8080,使用自定义处理器
	err := fasthttp.ListenAndServe(":8080", requestHandler)
	if err != nil {
		panic(err)
	}
}

ListenAndServeTLS(addr, certFile, keyFile string, handler RequestHandler) error

作用:启动 HTTPS 服务器

go 复制代码
func main() {
	// 传入证书和密钥路径
	err := fasthttp.ListenAndServeTLS(":443", "server.crt", "server.key", requestHandler)
	if err != nil {
		panic(err)
	}
}

Server 结构体(自定义服务器配置)

作用:精细化配置服务器(超时、最大连接数、工作池)

go 复制代码
func main() {
	server := &fasthttp.Server{
		Handler:      requestHandler,       // 处理器
		ReadTimeout:  5 * time.Second,      // 读取超时
		WriteTimeout: 5 * time.Second,      // 写入超时
		MaxConns:     100000,               // 最大连接数
		IdleTimeout:  10 * time.Second,     // 长连接空闲超时
	}

	// 启动服务器
	err := server.ListenAndServe(":8080")
	if err != nil {
		panic(err)
	}
}

Serve(l net.Listener, handler RequestHandler) error

作用:使用自定义 net.Listener 启动服务器

go 复制代码
func main() {
	ln, err := net.Listen("tcp", ":8080")
	if err != nil {
		panic(err)
	}
	// 基于自定义 listener 启动
	err = fasthttp.Serve(ln, requestHandler)
	if err != nil {
		panic(err)
	}
}

第二部分:RequestCtx 核心 API(请求处理必备)

RequestCtx 是 fasthttp 最核心的对象,封装了请求 + 响应 + 上下文。

获取请求方法、路径、URI

go 复制代码
func handler(ctx *fasthttp.RequestCtx) {
	// 1. 获取请求方法 GET/POST/PUT...
	method := ctx.Method() // []byte
	println("方法:", string(method))

	// 2. 获取请求路径
	path := ctx.Path()
	println("路径:", string(path))

	// 3. 获取完整请求URI
	uri := ctx.URI()
	println("完整URI:", string(uri.FullURI()))
}

响应数据(Write/WriteString/SetBody)

go 复制代码
func handler(ctx *fasthttp.RequestCtx) {
	// 写入字节
	ctx.Write([]byte("字节响应"))

	// 写入字符串(最常用)
	ctx.WriteString("字符串响应")

	// 直接设置响应体
	ctx.SetBody([]byte("直接设置body"))
}

设置响应状态码

go 复制代码
func handler(ctx *fasthttp.RequestCtx) {
	// 200 成功
	ctx.SetStatusCode(fasthttp.StatusOK)
	// 404 未找到
	// ctx.SetStatusCode(fasthttp.StatusNotFound)
	// 500 服务端错误
	// ctx.SetStatusCode(fasthttp.StatusInternalServerError)
}

请求 / 响应头操作

go 复制代码
func handler(ctx *fasthttp.RequestCtx) {
	// ✅ 获取请求头
	ua := ctx.Request.Header.Peek("User-Agent")
	println("UA:", string(ua))

	// ✅ 设置响应头
	ctx.Response.Header.Set("Server", "Fasthttp-Server")
	ctx.Response.Header.Add("X-Custom", "test")

	// ✅ 设置 Content-Type
	ctx.SetContentType("application/json; charset=utf-8")
}

获取 GET/POST 参数

go 复制代码
func handler(ctx *fasthttp.RequestCtx) {
	// GET 参数:?name=张三
	name := ctx.QueryArgs().Peek("name")

	// POST 表单参数
	age := ctx.PostArgs().Peek("age")

	// 获取参数(自动兼容 GET/POST)
	id := ctx.FormValue("id")

	println(string(name), string(age), string(id))
}

获取请求体

go 复制代码
func handler(ctx *fasthttp.RequestCtx) {
	// 获取原始请求体
	body := ctx.PostBody()
	println("请求体:", string(body))
}

重定向

go 复制代码
func handler(ctx *fasthttp.RequestCtx) {
	// 302 临时重定向
	ctx.Redirect("https://www.baidu.com", fasthttp.StatusFound)
	// 301 永久重定向
	// ctx.Redirect("/new", fasthttp.StatusMovedPermanently)
}

错误响应

go 复制代码
func handler(ctx *fasthttp.RequestCtx) {
	// 快速返回错误
	ctx.Error("参数错误", fasthttp.StatusBadRequest)
}

获取客户端 IP

go 复制代码
func handler(ctx *fasthttp.RequestCtx) {
	ip := ctx.RemoteIP()
	println("客户端IP:", ip.String())
}

第三部分:路由 API(高性能路由)

fasthttp 内置高性能路由,支持静态路由、参数路由、通配符。

基础路由注册

go 复制代码
func main() {
	router := func(ctx *fasthttp.RequestCtx) {
		// 路径匹配
		switch string(ctx.Path()) {
		case "/":
			ctx.WriteString("首页")
		case "/user":
			ctx.WriteString("用户页")
		default:
			ctx.Error("404 未找到", fasthttp.StatusNotFound)
		}
	}

	fasthttp.ListenAndServe(":8080", router)
}

官方推荐:router.Router 高级路由

需要安装路由扩展:

go 复制代码
go get github.com/fasthttp/router
go 复制代码
package main

import (
	"github.com/fasthttp/router"
	"github.com/valyala/fasthttp"
)

func main() {
	r := router.New()

	// 静态路由
	r.GET("/", homeHandler)
	// 参数路由 /user/123
	r.GET("/user/{id}", userHandler)
	// 通配符路由
	r.GET("/files/*filepath", filesHandler)

	// 启动服务器
	fasthttp.ListenAndServe(":8080", r.Handler)
}

func homeHandler(ctx *fasthttp.RequestCtx) {
	ctx.WriteString("首页")
}

func userHandler(ctx *fasthttp.RequestCtx) {
	// 获取路径参数
	id := ctx.UserValue("id").(string)
	ctx.WriteString("用户ID:" + id)
}

func filesHandler(ctx *fasthttp.RequestCtx) {
	fp := ctx.UserValue("filepath").(string)
	ctx.WriteString("文件路径:" + fp)
}

第四部分:Fasthttp 客户端 API

fasthttp 客户端同样比标准库 http.Client 快 5-10 倍。

快速 GET 请求

go 复制代码
func main() {
	// 快速GET:返回状态码、响应体、错误
	status, body, err := fasthttp.Get(nil, "https://www.baidu.com")
	if err != nil {
		panic(err)
	}
	println("状态码:", status)
	println("响应体:", string(body))
}

快速 POST 请求

go 复制代码
func main() {
	// POST 表单数据
	args := fasthttp.AcquireArgs()
	defer fasthttp.ReleaseArgs(args)
	args.Set("username", "test")
	args.Set("password", "123456")

	status, body, err := fasthttp.Post(nil, "http://127.0.0.1:8080/login", args)
	if err != nil {
		panic(err)
	}
	println(status, string(body))
}

自定义客户端(精细化配置)

go 复制代码
func main() {
	// 创建客户端
	client := &fasthttp.Client{
		ReadTimeout:  5 * time.Second,
		WriteTimeout: 5 * time.Second,
	}

	// 构造请求
	req := fasthttp.AcquireRequest()
	defer fasthttp.ReleaseRequest(req)
	req.SetRequestURI("http://127.0.0.1:8080")
	req.Header.SetMethod("GET")

	// 构造响应
	resp := fasthttp.AcquireResponse()
	defer fasthttp.ReleaseResponse(resp)

	// 发送请求
	err := client.Do(req, resp)
	if err != nil {
		panic(err)
	}

	println("响应:", string(resp.Body()))
}

池化请求 / 响应对象

go 复制代码
// 必须使用 Acquire/Release 避免内存泄漏
req := fasthttp.AcquireRequest()
defer fasthttp.ReleaseRequest(req) // 用完放回池

resp := fasthttp.AcquireResponse()
defer fasthttp.ReleaseResponse(resp)

第五部分:工具类 API

URI 解析

go 复制代码
func handler(ctx *fasthttp.RequestCtx) {
	u := ctx.URI()
	println("协议:", string(u.Scheme()))
	println("主机:", string(u.Host()))
	println("路径:", string(u.Path()))
	println("查询参数:", string(u.QueryString()))
}

字节 / 字符串工具

go 复制代码
// 安全转换 []byte <-> string(零拷贝)
b := []byte("test")
s := fasthttp.StringToByte("test")
b2s := fasthttp.ByteToString(b)

状态码常量

fasthttp 内置所有 HTTP 状态码:

go 复制代码
fasthttp.StatusOK // 200
fasthttp.StatusNotFound // 404
fasthttp.StatusBadRequest // 400
fasthttp.StatusInternalServerError // 500

Gzip 压缩

go 复制代码
rawHandler := func(ctx *fasthttp.RequestCtx) {
	ctx.WriteString("long text content...")
}
// 自动压缩响应
compressHandler := fasthttp.CompressHandler(rawHandler)
fasthttp.ListenAndServe(":8080", compressHandler)

静态文件服务

go 复制代码
// 静态文件目录 ./static,访问 /static/*
staticHandler := fasthttp.FSHandler("./static", 0)
fasthttp.ListenAndServe(":8080", staticHandler)

表单提交 POST

go 复制代码
args := fasthttp.Args{}
args.Set("username", "admin")
args.Set("password", "123456")
req.SetBody(args.QueryString())
req.Header.SetContentType("application/x-www-form-urlencoded")

PipelineClient 批量并发请求(高吞吐)适合批量调用第三方接口

go 复制代码
pipeline := fasthttp.PipelineClient{
	Client: client,
}
// 批量发送多个req
var reqs []*fasthttp.Request
// ...填充reqs
resps, err := pipeline.Do(reqs...)

Args 参数工具(URL 参数、表单)

go 复制代码
var args fasthttp.Args
args.Set("id", "100")
args.Set("name", "zhangsan")
// 拼接成 query string
qs := args.QueryString() // id=100&name=zhangsan

URI 工具

go 复制代码
u := fasthttp.AcquireURI()
u.SetScheme("https")
u.SetHost("baidu.com")
u.SetPath("/search")
u.QueryArgs().Set("wd", "go")
fmt.Println(string(u.FullURI())) // https://baidu.com/search?wd=go
fasthttp.ReleaseURI(u)

完整 API 清单(速查)

  1. 服务器
    ListenAndServe
    ListenAndServeTLS
    Serve
    ServeTLS
  2. Server 结构体
    RequestCtx
    Method(), Path(), URI()
    Write(), WriteString(), SetBody()
    SetStatusCode(), SetContentType()
    Request.Header, Response.Header
    QueryArgs(), PostArgs(), FormValue()
    PostBody(), RemoteIP()
    Redirect(), Error()
    UserValue()(路由参数)
  3. 客户端
    Get(), Post(), Put(), Delete()
    Client{}
    AcquireRequest(), ReleaseRequest()
    AcquireResponse(), ReleaseResponse()
    AcquireArgs(), ReleaseArgs()
  4. 路由
    router.New()
    GET/POST/PUT/DELETE 注册
    {param} 路径参数
  • 通配符
  1. 工具
    URI 解析
    字节 / 字符串零拷贝转换
    HTTP 状态码常量

总结

  • fasthttp 核心优势:对象池化、零内存分配、低 GC、高并发,性能远超标准库 net/http
  • 核心原理:sync.Pool 复用对象 + 零拷贝 + 长连接 + 精简上下文
  • 使用规范:必须用 Acquire/Release 管理请求 / 响应对象,避免内存泄漏
  • 适用场景:高并发 API、网关、代理、压测;不适合 HTTP/2、WebSocket 重度使用

在实际项目中使用 fasthttp

项目目录

fast-api/

├── cmd

│ └── server

│ └── main.go

├── config

│ ├── app.yaml

│ └── config.go

├── internal

│ ├── handler

│ │ ├── demo_handler.go

│ │ └── user_handler.go

│ ├── middleware

│ │ ├── auth.go

│ │ ├── cors.go

│ │ ├── logger.go

│ │ └── recovery.go

│ ├── repo

│ │ └── user_repo.go

│ └── service

│ ├── demo_service.go

│ └── user_service.go

├── pkg

│ ├── httpclient

│ │ └── client.go

│ ├── resp

│ │ └── response.go

│ └── validator

│ └── validate.go

├── router

│ ├── group.go

│ └── router.go

├── go.mod

└── go.sum

go.mod

go 复制代码
module fast-api

go 1.21

require (
	github.com/fasthttp/router v1.4.0
	github.com/go-playground/validator/v10 v10.15.0
	github.com/spf13/viper v1.18.2
	github.com/valyala/fasthttp v1.51.0
)

config/app.yaml

go 复制代码
app:
  name: fast-api
  port: 8080
  read_timeout: 3000
  write_timeout: 3000
  idle_timeout: 10000
  max_conns: 100000
shutdown_timeout: 10
auth_token: "admin123456"

config/config.go

go 复制代码
package config

import (
	"github.com/spf13/viper"
	"log"
	"time"
)

var Conf AppConfig

type AppConfig struct {
	App struct {
		Name         string
		Port         string
		ReadTimeout  time.Duration
		WriteTimeout time.Duration
		IdleTimeout  time.Duration
		MaxConns     int
	}
	ShutdownTimeout time.Duration
	AuthToken      string
}

func Init() {
	viper.SetConfigFile("config/app.yaml")
	if err := viper.ReadInConfig(); err != nil {
		log.Fatalf("read config err: %v", err)
	}
	Conf.App.Name = viper.GetString("app.name")
	Conf.App.Port = viper.GetString("app.port")
	Conf.App.ReadTimeout = viper.GetDuration("app.read_timeout") * time.Millisecond
	Conf.App.WriteTimeout = viper.GetDuration("app.write_timeout") * time.Millisecond
	Conf.App.IdleTimeout = viper.GetDuration("app.idle_timeout") * time.Millisecond
	Conf.App.MaxConns = viper.GetInt("app.max_conns")
	Conf.ShutdownTimeout = viper.GetDuration("shutdown_timeout") * time.Second
	Conf.AuthToken = viper.GetString("auth_token")
}

pkg/resp/response.go

go 复制代码
package resp

import (
	"encoding/json"
	"github.com/valyala/fasthttp"
)

type Response struct {
	Code    int         `json:"code"`
	Msg     string      `json:"msg"`
	Data    interface{} `json:"data,omitempty"`
	TraceID string      `json:"traceId"`
}

const (
	CodeSuccess = 0
	CodeFail    = 400
	CodeAuth    = 401
	CodeServer  = 500
)

func JSON(ctx *fasthttp.RequestCtx, code int, msg string, data any) {
	ctx.SetContentType("application/json; charset=utf-8")
	traceID := ctx.UserValue("traceId").(string)
	_ = json.NewEncoder(ctx).Encode(Response{
		Code:    code,
		Msg:     msg,
		Data:    data,
		TraceID: traceID,
	})
}

func Success(ctx *fasthttp.RequestCtx, data any) {
	JSON(ctx, CodeSuccess, "success", data)
}

func Fail(ctx *fasthttp.RequestCtx, msg string) {
	JSON(ctx, CodeFail, msg, nil)
}

func AuthFail(ctx *fasthttp.RequestCtx) {
	JSON(ctx, CodeAuth, "token invalid", nil)
}

func ServerErr(ctx *fasthttp.RequestCtx) {
	JSON(ctx, CodeServer, "server internal error", nil)
}

pkg/validator/validate.go

go 复制代码
package validator

import (
	"github.com/go-playground/validator/v10"
)

var validate *validator.Validate

func Init() {
	validate = validator.New()
}

func Struct(obj any) error {
	return validate.Struct(obj)
}

pkg/httpclient/client.go

go 复制代码
package httpclient

import (
	"encoding/json"
	"github.com/valyala/fasthttp"
	"log"
)

var client = &fasthttp.Client{
	ReadTimeout:  3 * time.Second,
	WriteTimeout: 3 * time.Second,
}

func Get(url string) ([]byte, error) {
	req := fasthttp.AcquireRequest()
	defer fasthttp.ReleaseRequest(req)
	resp := fasthttp.AcquireResponse()
	defer fasthttp.ReleaseResponse(resp)

	req.SetRequestURI(url)
	req.Header.SetMethod(fasthttp.MethodGet)
	if err := client.Do(req, resp); err != nil {
		return nil, err
	}
	return resp.Body(), nil
}

func PostJSON(url string, body any) ([]byte, error) {
	req := fasthttp.AcquireRequest()
	defer fasthttp.ReleaseRequest(req)
	resp := fasthttp.AcquireResponse()
	defer fasthttp.ReleaseResponse(resp)

	req.SetRequestURI(url)
	req.Header.SetMethod(fasthttp.MethodPost)
	req.Header.SetContentType("application/json")
	_ = json.NewEncoder(req.BodyWriter()).Encode(body)

	if err := client.Do(req, resp); err != nil {
		log.Printf("http post err: %v", err)
		return nil, err
	}
	return resp.Body(), nil
}

internal/middleware/cors.go

go 复制代码
package middleware

import "github.com/valyala/fasthttp"

func Cors(next fasthttp.RequestHandler) fasthttp.RequestHandler {
	return func(ctx *fasthttp.RequestCtx) {
		ctx.Response.Header.Set("Access-Control-Allow-Origin", "*")
		ctx.Response.Header.Set("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE,OPTIONS")
		ctx.Response.Header.Set("Access-Control-Allow-Headers", "Content-Type,Authorization")
		if string(ctx.Method()) == fasthttp.MethodOptions {
			ctx.SetStatusCode(fasthttp.StatusOK)
			return
		}
		next(ctx)
	}
}

internal/middleware/recovery.go

go 复制代码
package middleware

import (
	"fast-api/pkg/resp"
	"github.com/valyala/fasthttp"
	"log"
)

func Recovery(next fasthttp.RequestHandler) fasthttp.RequestHandler {
	return func(ctx *fasthttp.RequestCtx) {
		defer func() {
			if err := recover(); err != nil {
				log.Printf("panic recovered: %v", err)
				resp.ServerErr(ctx)
			}
		}()
		next(ctx)
	}
}

internal/middleware/logger.go

go 复制代码
package middleware

import (
	"fast-api/pkg/resp"
	"github.com/valyala/fasthttp"
	"log"
	"math/rand"
	"time"
)

func Logger(next fasthttp.RequestHandler) fasthttp.RequestHandler {
	return func(ctx *fasthttp.RequestCtx) {
		start := time.Now()
		// 生成traceId
		traceID := randString(16)
		ctx.SetUserValue("traceId", traceID)

		next(ctx)

		cost := time.Since(start)
		method := string(ctx.Method())
		path := string(ctx.Path())
		status := ctx.Response.StatusCode()
		ip := ctx.RemoteIP().String()
		log.Printf("[%s] %s %s status=%d ip=%s cost=%s", traceID, method, path, status, ip, cost)
	}
}

func randString(n int) string {
	letters := []rune("0123456789abcdefghijklmnopqrstuvwxyz")
	b := make([]rune, n)
	for i := range b {
		b[i] = letters[rand.Intn(len(letters))]
	}
	return string(b)
}

internal/middleware/auth.go

go 复制代码
package middleware

import (
	"fast-api/config"
	"fast-api/pkg/resp"
	"github.com/valyala/fasthttp"
)

func Auth(next fasthttp.RequestHandler) fasthttp.RequestHandler {
	return func(ctx *fasthttp.RequestCtx) {
		token := string(ctx.Request.Header.Peek("Authorization"))
		if token != config.Conf.AuthToken {
			resp.AuthFail(ctx)
			return
		}
		next(ctx)
	}
}

internal/repo/user_repo.go

go 复制代码
package repo

type User struct {
	ID   int    `json:"id"`
	Name string `json:"name"`
	Age  int    `json:"age"`
}

func GetUserByID(id int) *User {
	// 模拟数据库查询
	return &User{
		ID:   id,
		Name: "test_user",
		Age:  22,
	}
}

internal/service/user_service.go

go 复制代码
package service

import (
	"fast-api/internal/repo"
)

func GetUserInfo(uid int) (*repo.User, error) {
	user := repo.GetUserByID(uid)
	return user, nil
}

internal/service/demo_service.go

go 复制代码
package service

func Hello(name string) string {
	return "hello " + name
}

internal/handler/demo_handler.go

go 复制代码
package handler

import (
	"fast-api/internal/service"
	"fast-api/pkg/resp"
	"github.com/valyala/fasthttp"
)

func Hello(ctx *fasthttp.RequestCtx) {
	// FormValue 兼容GET/表单参数
	name := string(ctx.FormValue("name"))
	msg := service.Hello(name)
	resp.Success(ctx, map[string]any{"msg": msg})
}

type ReqDemo struct {
	Text string `json:"text" validate:"required,min=2"`
}

func PostDemo(ctx *fasthttp.RequestCtx) {
	var req ReqDemo
	body := ctx.PostBody()
	if err := json.Unmarshal(body, &req); err != nil {
		resp.Fail(ctx, "json parse error")
		return
	}
	if err := validator.Struct(&req); err != nil {
		resp.Fail(ctx, err.Error())
		return
	}
	resp.Success(ctx, req)
}

internal/handler/user_handler.go

go 复制代码
package handler

import (
	"fast-api/internal/service"
	"fast-api/pkg/resp"
	"github.com/valyala/fasthttp"
	"strconv"
)

func GetUser(ctx *fasthttp.RequestCtx) {
	// 路径参数
	idStr := ctx.UserValue("id").(string)
	uid, err := strconv.Atoi(idStr)
	if err != nil {
		resp.Fail(ctx, "invalid user id")
		return
	}
	user, err := service.GetUserInfo(uid)
	if err != nil {
		resp.Fail(ctx, "user not found")
		return
	}
	resp.Success(ctx, user)
}

router/group.go

go 复制代码
package router

import (
	"fast-api/internal/handler"
	"fast-api/internal/middleware"
	"github.com/fasthttp/router"
)

func registerPublic(r *router.Router) {
	// 全局中间件:日志、跨域、panic恢复
	r.GET("/", middleware.Cors(middleware.Logger(middleware.Recovery(handler.Hello))))
}

func registerAPI(r *router.Router) {
	api := r.Group("/api/v1")
	// 分组增加鉴权中间件
	api.GET("/user/{id}", middleware.Auth(middleware.Cors(middleware.Logger(middleware.Recovery(handler.GetUser)))))
	api.POST("/demo", middleware.Auth(middleware.Cors(middleware.Logger(middleware.Recovery(handler.PostDemo)))))
}

router/router.go

go 复制代码
package router

import "github.com/fasthttp/router"

func InitRouter() *router.Router {
	r := router.New()
	registerPublic(r)
	registerAPI(r)
	return r
}

cmd/server/main.go

go 复制代码
package main

import (
	"context"
	"fast-api/config"
	"fast-api/pkg/validator"
	"fast-api/router"
	"github.com/valyala/fasthttp"
	"log"
	"os"
	"os/signal"
	"syscall"
)

func main() {
	// 初始化配置
	config.Init()
	// 参数校验器初始化
	validator.Init()
	// 初始化路由
	r := router.InitRouter()

	// 构建fasthttp服务
	srv := &fasthttp.Server{
		Handler:      r.Handler,
		ReadTimeout:  config.Conf.App.ReadTimeout,
		WriteTimeout: config.Conf.App.WriteTimeout,
		IdleTimeout:  config.Conf.App.IdleTimeout,
		MaxConns:     config.Conf.App.MaxConns,
		TCPKeepalive: true,
	}

	// 信号监听
	sigChan := make(chan os.Signal, 1)
	signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)

	// 异步启动服务
	go func() {
		log.Printf("server listen on :%s", config.Conf.App.Port)
		if err := srv.ListenAndServe(":" + config.Conf.App.Port); err != nil && err != fasthttp.ErrServerClosed {
			log.Fatalf("listen err: %v", err)
		}
	}()

	// 阻塞等待关闭信号
	sig := <-sigChan
	log.Printf("receive signal: %s, start graceful shutdown", sig.String())
	signal.Stop(sigChan)

	// 优雅关闭
	ctx, cancel := context.WithTimeout(context.Background(), config.Conf.ShutdownTimeout)
	defer cancel()
	if err := srv.Shutdown(ctx); err != nil {
		log.Fatalf("shutdown err: %v", err)
	}
	log.Println("server exit success")
}

其他

针对json.NewEncoder(ctx).Encode()

fasthttp 场景下不推荐这么写

  • 问题 1:不会自动设置 Content-Type
    json.Encoder 只写内容,不会给响应头加 Content-Type: application/json,浏览器 / 客户端会识别成普通文本。
    需要手动补充:
    运行
go 复制代码
ctx.SetContentType("application/json; charset=utf-8")
  • 问题 2:性能差,违背 fasthttp 设计初衷
    fasthttp 主打对象池、减少内存分配、低 GC:json.NewEncoder(ctx) 每次请求都会新建一个 Encoder 对象,堆内存分配,增加 GC 压力;
    标准 Encoder 内部缓冲区没有复用,高 QPS 下开销明显;
  • 问题 3:自带多余换行符
    .Encode() 输出末尾强制加 \n,部分前端解析无影响,但接口返回格式不纯净。

fasthttp 标准高性能写法(推荐替换上面代码)

  • 方案 1:预序列化 + Write(性能最优)
go 复制代码
import "encoding/json"

// 1. 先序列化
resp := Response{Code: code, Msg: msg, Data: data, TraceID: traceID}
buf, err := json.Marshal(resp)
if err != nil {
	ctx.Error("json marshal fail", fasthttp.StatusInternalServerError)
	return
}
// 2. 设置json头
ctx.SetContentType("application/json; charset=utf-8")
// 3. 写入响应
ctx.Write(buf)
  • 复用 bytebuffer 极致优化(高并发网关)
    借助 fasthttp 自带缓冲池减少分配:
go 复制代码
buf := fasthttp.AcquireByteBuffer()
defer fasthttp.ReleaseByteBuffer(buf)

resp := Response{Code: code, Msg: msg, Data: data, TraceID: traceID}
err := json.NewEncoder(buf).Encode(&resp)
if err != nil {
	ctx.Error("marshal err", 500)
	return
}
ctx.SetContentType("application/json")
ctx.Write(buf.B)