跳到主要内容

Fiber

Fiber 是一个受 Express.js 启发的 Go Web 框架,构建在 Fasthttp 之上,以其极致的性能和简洁的 API 设计而闻名。它是目前 Go 语言中最快的 Web 框架之一。

简介

Fiber 特性

Fiber 核心特性:

  • 极致性能: 基于 Fasthttp,性能比标准 net/http 快得多
  • Express 风格: API 设计类似 Express.js,学习成本低
  • 零内存路由: 高效的路由匹配
  • 静态文件服务: 内置静态文件服务
  • 中间件丰富: 大量内置中间件
  • WebSocket 支持: 原生 WebSocket 支持
  • 模板引擎: 支持多种模板引擎
  • 国际化: 内置 i18n 支持

适用场景:

  • 需要极致性能的 Web 应用
  • 高并发 API 服务
  • 实时应用
  • 微服务架构
  • 从 Node.js 迁移到 Go 的项目

安装 Fiber

# 初始化 Go module
go mod init myproject

# 安装 Fiber
go get -u github.com/gofiber/fiber/v2

第一个 Fiber 应用

package main

import (
"github.com/gofiber/fiber/v2"
)

func main() {
// 创建 Fiber 应用
app := fiber.New()

// 定义路由
app.Get("/", func(c *fiber.Ctx) error {
return c.SendString("Hello, Fiber!")
})

// 启动服务
app.Listen(":8080")
}

核心概念

1. 路由 (Routing)

基本路由

package main

import (
"github.com/gofiber/fiber/v2"
)

func main() {
app := fiber.New()

// GET 请求
app.Get("/users", getUsers)

// POST 请求
app.Post("/users", createUser)

// PUT 请求
app.Put("/users/:id", updateUser)

// DELETE 请求
app.Delete("/users/:id", deleteUser)

// 所有方法
app.All("/all", func(c *fiber.Ctx) error {
return c.SendString("All methods")
})

app.Listen(":8080")
}

路径参数

// 路径参数
app.Get("/users/:id", func(c *fiber.Ctx) error {
id := c.Params("id")
return c.SendString("User ID: " + id)
})

// 可选参数
app.Get("/users/:id?", func(c *fiber.Ctx) error {
id := c.Params("id")
if id == "" {
return c.SendString("All users")
}
return c.SendString("User ID: " + id)
})

// 通配符
app.Get("/files/*", func(c *fiber.Ctx) error {
filePath := c.Params("*")
return c.SendString("File path: " + filePath)
})

// 正则表达式
app.Get("/users/:id<[0-9]+>", func(c *fiber.Ctx) error {
id := c.Params("id")
return c.SendString("User ID: " + id)
})

查询参数

app.Get("/search", func(c *fiber.Ctx) error {
keyword := c.Query("keyword")
page := c.Query("page", "1") // 默认值
limit := c.Query("limit", "10")

return c.JSON(fiber.Map{
"keyword": keyword,
"page": page,
"limit": limit,
})
})

// 获取所有查询参数
app.Get("/params", func(c *fiber.Ctx) error {
return c.JSON(c.Queries())
})

2. 路由分组

func main() {
app := fiber.New()

// API v1 路由组
v1 := app.Group("/api/v1")
v1.Get("/users", getUsers)
v1.Get("/posts", getPosts)

// 带中间件的路由组
api := app.Group("/api", func(c *fiber.Ctx) error {
c.Set("Version", "v1")
return c.Next()
})

api.Get("/list", func(c *fiber.Ctx) error {
return c.SendString("API List")
})

// 嵌套路由组
auth := app.Group("/auth")
auth.Post("/login", login)
auth.Post("/register", register)

app.Listen(":8080")
}

3. 中间件 (Middleware)

内置中间件

import (
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/cors"
"github.com/gofiber/fiber/v2/middleware/logger"
"github.com/gofiber/fiber/v2/middleware/recover"
"github.com/gofiber/fiber/v2/middleware/compress"
"github.com/gofiber/fiber/v2/middleware/limiter"
)

func main() {
app := fiber.New()

// 日志中间件
app.Use(logger.New())

// 恢复中间件
app.Use(recover.New())

// CORS 中间件
app.Use(cors.New())

// 压缩中间件
app.Use(compress.New(compress.Config{
Level: compress.LevelBestSpeed,
}))

// 限流中间件
app.Use(limiter.New(limiter.Config{
Max: 100,
Expiration: 1 * time.Minute,
}))

app.Listen(":8080")
}

自定义中间件

// 自定义中间件函数
func customMiddleware(c *fiber.Ctx) error {
println("👉 Before request")

// 继续处理
err := c.Next()

println("👈 After request")

return err
}

// 使用自定义中间件
app.Use(customMiddleware)

// 带配置的中间件
func authMiddleware(config fiber.Map) fiber.Handler {
return func(c *fiber.Ctx) error {
token := c.Get("Authorization")

if token != config["token"] {
return c.Status(401).JSON(fiber.Map{
"error": "Unauthorized",
})
}

return c.Next()
}
}

// 使用带配置的中间件
app.Use(authMiddleware(fiber.Map{
"token": "secret-token",
}))

中间件控制

// 只在特定路由应用中间件
app.Get("/protected", authMiddleware(), func(c *fiber.Ctx) error {
return c.SendString("Protected route")
})

// 多个中间件
app.Get("/secure",
authMiddleware(),
rateLimitMiddleware(),
func(c *fiber.Ctx) error {
return c.SendString("Secure route")
},
)

// 跳过中间件
app.Get("/public", func(c *fiber.Ctx) error {
return c.SendString("Public route")
})

4. 请求处理

获取请求数据

// JSON 数据
type User struct {
Name string `json:"name"`
Email string `json:"email"`
Age int `json:"age"`
}

app.Post("/users", func(c *fiber.Ctx) error {
user := new(User)

// 解析 JSON
if err := c.BodyParser(user); err != nil {
return c.Status(400).JSON(fiber.Map{
"error": "Cannot parse JSON",
})
}

return c.JSON(user)
})

// 表单数据
app.Post("/form", func(c *fiber.Ctx) error {
name := c.FormValue("name")
email := c.FormValue("email")

// 获取文件
file, err := c.FormFile("file")
if err != nil {
return err
}

// 保存文件
err = c.SaveFile(file, fmt.Sprintf("./uploads/%s", file.Filename))
if err != nil {
return err
}

return c.JSON(fiber.Map{
"name": name,
"email": email,
"file": file.Filename,
})
})

// 请求头
app.Get("/headers", func(c *fiber.Ctx) error {
userAgent := c.Get("User-Agent")
authorization := c.Get("Authorization")

return c.JSON(fiber.Map{
"user_agent": userAgent,
"authorization": authorization,
})
})

// 请求体
app.Post("/raw", func(c *fiber.Ctx) error {
body := c.Body()
return c.Send(body)
})

5. 响应处理

// JSON 响应
app.Get("/json", func(c *fiber.Ctx) error {
return c.JSON(fiber.Map{
"message": "Hello, Fiber!",
"status": "success",
})
})

// JSONP 响应
app.Get("/jsonp", func(c *fiber.Ctx) error {
return c.JSONP(fiber.Map{
"message": "Hello, Fiber!",
})
})

// XML 响应
app.Get("/xml", func(c *fiber.Ctx) error {
return c.XML(fiber.Map{
"message": "Hello, Fiber!",
})
})

// 字符串响应
app.Get("/string", func(c *fiber.Ctx) error {
return c.SendString("Hello, Fiber!")
})

// HTML 响应
app.Get("/html", func(c *fiber.Ctx) error {
return c.SendString("<h1>Hello, Fiber!</h1>")
})

// 设置响应头
app.Get("/headers", func(c *fiber.Ctx) error {
c.Set("Content-Type", "application/json")
c.Set("X-Custom-Header", "value")
return c.SendString("Headers set")
})

// 状态码
app.Get("/status", func(c *fiber.Ctx) error {
return c.Status(201).JSON(fiber.Map{
"message": "Created",
})
})

// 文件下载
app.Get("/download", func(c *fiber.Ctx) error {
return c.Download("./files/file.pdf", "download.pdf")
})

// 流式响应
app.Get("/stream", func(c *fiber.Ctx) error {
c.Context().SetContentType("text/plain")
c.WriteString("Hello, ")
c.WriteString("Fiber!")
return nil
})

6. 错误处理

// 全局错误处理
app.Use(func(c *fiber.Ctx) error {
// 处理链中的错误
err := c.Next()

if err != nil {
// 返回 JSON 错误响应
code := fiber.StatusInternalServerError

if e, ok := err.(*fiber.Error); ok {
code = e.Code
}

return c.Status(code).JSON(fiber.Map{
"error": err.Error(),
})
}

return nil
})

// 自定义错误
app.Get("/error", func(c *fiber.Ctx) error {
return fiber.NewError(404, "Custom error message")
})

// 404 处理
app.Use(func(c *fiber.Ctx) error {
return c.Status(404).JSON(fiber.Map{
"error": "Not Found",
})
})

模板引擎

import (
"github.com/gofiber/fiber/v2"
"github.com/gofiber/template/html"
)

func main() {
// 创建模板引擎
engine := html.New("./views", ".html")

app := fiber.New(fiber.Config{
Views: engine,
})

// 渲染模板
app.Get("/", func(c *fiber.Ctx) error {
return c.Render("index", fiber.Map{
"Title": "Hello, Fiber!",
})
})

app.Listen(":8080")
}

静态文件服务

// 静态文件目录
app.Static("/", "./public")

// 自定义前缀
app.Static("/prefix", "./public")

// 多个静态目录
app.Static("/css", "./assets/css")
app.Static("/js", "./assets/js")
app.Static("/images", "./assets/images")

// 单个文件
app.Static("/favicon.ico", "./favicon.ico")

WebSocket 支持

import (
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/websocket"
)

app.Use("/ws", func(c *fiber.Ctx) error {
// WebSocket 升级
if websocket.IsWebSocketUpgrade(c) {
c.Locals("allowed", true)
return c.Next()
}
return fiber.ErrUpgradeRequired
})

app.Get("/ws", websocket.New(func(c *websocket.Conn) {
for {
mt, msg, err := c.ReadMessage()
if err != nil {
break
}

if err := c.WriteMessage(mt, msg); err != nil {
break
}
}
}))

数据验证

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

type User struct {
Name string `json:"name" validate:"required,min=3,max=50"`
Email string `json:"email" validate:"required,email"`
Age int `json:"age" validate:"gte=0,lte=130"`
}

app.Post("/users", func(c *fiber.Ctx) error {
user := new(User)

if err := c.BodyParser(user); err != nil {
return c.Status(400).JSON(fiber.Map{
"error": "Cannot parse JSON",
})
}

if err := validator.New().Struct(user); err != nil {
return c.Status(400).JSON(fiber.Map{
"error": err.Error(),
})
}

return c.JSON(user)
})

实战示例

RESTful API

package main

import (
"github.com/gofiber/fiber/v2"
"strconv"
)

type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
}

var (
users = map[int]User{
1: {ID: 1, Name: "Alice", Email: "alice@example.com"},
2: {ID: 2, Name: "Bob", Email: "bob@example.com"},
}
seq = 3
)

func main() {
app := fiber.New(fiber.Config{
ErrorHandler: func(c *fiber.Ctx, err error) error {
code := fiber.StatusInternalServerError
if e, ok := err.(*fiber.Error); ok {
code = e.Code
}
return c.Status(code).JSON(fiber.Map{
"error": err.Error(),
})
},
})

// 路由
app.Get("/users", getUsers)
app.Get("/users/:id", getUser)
app.Post("/users", createUser)
app.Put("/users/:id", updateUser)
app.Delete("/users/:id", deleteUser)

app.Listen(":8080")
}

func getUsers(c *fiber.Ctx) error {
userList := make([]User, 0, len(users))
for _, user := range users {
userList = append(userList, user)
}
return c.JSON(userList)
}

func getUser(c *fiber.Ctx) error {
id, _ := strconv.Atoi(c.Params("id"))
user, ok := users[id]
if !ok {
return fiber.NewError(fiber.StatusNotFound, "User not found")
}
return c.JSON(user)
}

func createUser(c *fiber.Ctx) error {
user := new(User)
if err := c.BodyParser(user); err != nil {
return err
}

user.ID = seq
seq++
users[user.ID] = *user

return c.Status(fiber.StatusCreated).JSON(user)
}

func updateUser(c *fiber.Ctx) error {
id, _ := strconv.Atoi(c.Params("id"))
user := new(User)
if err := c.BodyParser(user); err != nil {
return err
}

user.ID = id
users[id] = *user

return c.JSON(users[id])
}

func deleteUser(c *fiber.Ctx) error {
id, _ := strconv.Atoi(c.Params("id"))
delete(users, id)

return c.SendStatus(fiber.StatusNoContent)
}

最佳实践

1. 项目结构

my-fiber-app/
├── main.go
├── config/
│ └── config.go
├── controllers/
│ └── user_controller.go
├── models/
│ └── user.go
├── routes/
│ └── routes.go
├── middlewares/
│ └── auth.go
└── utils/
└── response.go

2. 配置管理

import "github.com/spf13/viper"

func loadConfig() {
viper.SetConfigName("config")
viper.SetConfigType("yaml")
viper.AddConfigPath(".")
viper.AddConfigPath("./config")

if err := viper.ReadInConfig(); err != nil {
panic(err)
}
}

func main() {
loadConfig()

port := viper.GetString("server.port")

app := fiber.New()
app.Listen(":" + port)
}

3. 优雅关闭

func main() {
app := fiber.New()

// 启动服务器
go func() {
if err := app.Listen(":8080"); err != nil {
log.Println(err)
}
}()

// 等待中断信号
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
<-c

// 优雅关闭
if err := app.Shutdown(); err != nil {
log.Println(err)
}
}

4. 使用 Fiber 上下文存储

// 存储数据
app.Use(func(c *fiber.Ctx) error {
c.Locals("user", "Alice")
return c.Next()
})

// 获取数据
app.Get("/", func(c *fiber.Ctx) error {
user := c.Locals("user")
return c.SendString("User: " + user.(string))
})

性能优化

1. 启用 prefork

app := fiber.New(fiber.Config{
Prefork: true, // 启用多进程
StrictRouting: true,
CaseSensitive: true,
ServerHeader: "Fiber",
AppName: "My App v1.0.0",
})

2. 禁用调试模式

app := fiber.New(fiber.Config{
EnablePrintRoutes: false,
DisableStartupMessage: false,
})

3. 使用连接池

var httpClient = &http.Client{
Timeout: 10 * time.Second,
Transport: &http.Transport{
MaxIdleConns: 100,
MaxIdleConnsPerHost: 100,
IdleConnTimeout: 90 * time.Second,
},
}

常见问题

1. CORS 配置

import "github.com/gofiber/fiber/v2/middleware/cors"

app.Use(cors.New(cors.Config{
AllowOrigins: "http://localhost:3000",
AllowMethods: "GET,POST,PUT,DELETE",
AllowHeaders: "Origin, Content-Type, Accept",
AllowCredentials: true,
MaxAge: 86400,
}))

2. 日志配置

import "github.com/gofiber/fiber/v2/middleware/logger"

app.Use(logger.New(logger.Config{
Format: "[${time}] ${status} - ${method} ${path}\n",
TimeFormat: "2006-01-02 15:04:05",
TimeZone: "Local",
}))

总结

Fiber 是一个性能卓越、易于使用的 Web 桵架,特别适合追求极致性能的项目。它基于 Fasthttp 构建,在处理高并发场景时表现出色。同时,其类似 Express.js 的 API 设计使得开发者能够快速上手。对于需要高性能、高并发的 Web 应用,Fiber 是一个非常好的选择。

参考资料