今天上午又开了一上午会,没办法,竞争对手太给力,无聊看看fiber,最近一直在玩fiber,minty也是基于fiber,也提了一些issue,社区还算活跃
今天看几个基础结构吧
首先还是看app文件,很多核心结构都在里面
go// Version 表示当前 fiber 包的版本
const Version = "2.52.5"
// Handler 定义了一个用于处理 HTTP 请求的函数类型。
type Handler = func(*Ctx) error // 路由的Handler和中间件都是一个Handler
// Map 是 map[string]interface{} 的快捷方式,适用于 JSON 返回值,类似于gin.H
type Map map[string]interface{}
// Storage 接口用于与不同的数据库/键值存储提供者进行通信
type Storage interface {
// Get 获取给定键的值。
// 如果键不存在,则返回 `nil, nil`
Get(key string) ([]byte, error)
// Set 存储给定键的值,并附带一个过期时间,0 表示不过期。
// 空键或空值将被忽略,不会返回错误。
Set(key string, val []byte, exp time.Duration) error
// Delete 删除给定键的值。
// 如果存储中不包含该键,则不会返回错误。
Delete(key string) error
// Reset 重置存储并删除所有键。
Reset() error
// Close 关闭存储,并停止任何正在运行的垃圾收集器和打开的连接。
Close() error
}
接下来是ErrorHandler,它类似于全局异常捕获,允许你统一处理未处理的异常
go// ErrorHandler 定义了一个函数,该函数将处理堆栈中任何处理程序返回的所有错误
//
// cfg := fiber.Config{}
// cfg.ErrorHandler = func(c *Ctx, err error) error {
// code := StatusInternalServerError
// var e *fiber.Error
// if errors.As(err, &e) {
// code = e.Code
// }
// c.Set(HeaderContentType, MIMETextPlainCharsetUTF8)
// return c.Status(code).SendString(err.Error())
// }
// app := fiber.New(cfg)
type ErrorHandler = func(*Ctx, error) error
// Error 表示在处理请求时发生的错误。
type Error struct {
Code int `json:"code"`
Message string `json:"message"`
}
下面是一个示例
gopackage main
import (
"errors"
"fmt"
"github.com/gofiber/fiber/v2"
"net/http"
)
// 自定义错误类型
type CustomError struct {
Code int
Message string
}
// 实现 Error 接口
func (e *CustomError) Error() string {
return e.Message
}
func main() {
// 创建 Fiber 应用
app := fiber.New(fiber.Config{
// 配置 ErrorHandler
ErrorHandler: func(c *fiber.Ctx, err error) error {
// 获取 HTTP 状态码,默认为 500
code := fiber.StatusInternalServerError
// 检查是否是自定义错误类型
var e *CustomError
if errors.As(err, &e) {
code = e.Code
}
// 设置响应头
c.Set(fiber.HeaderContentType, fiber.MIMETextPlainCharsetUTF8)
// 返回错误信息
return c.Status(code).SendString(err.Error())
},
})
// 定义一个路由,故意抛出一个错误
app.Get("/error", func(c *fiber.Ctx) error {
// 抛出一个自定义错误
return &CustomError{
Code: http.StatusBadRequest,
Message: "这是一个自定义错误",
}
})
// 定义另一个路由,故意抛出一个未处理的错误
app.Get("/panic", func(c *fiber.Ctx) error {
// 抛出一个未处理的错误
return fmt.Errorf("这是一个未处理的错误")
})
// 启动应用
err := app.Listen(":3000")
if err != nil {
fmt.Println("启动服务器失败:", err)
}
}
接下来是App结构
go
// App denotes the Fiber application.
type App struct {
mutex sync.Mutex
// Route stack divided by HTTP methods
stack [][]*Route
// Route stack divided by HTTP methods and route prefixes
treeStack []map[string][]*Route
// contains the information if the route stack has been changed to build the optimized tree
routesRefreshed bool
// Amount of registered routes
routesCount uint32
// Amount of registered handlers
handlersCount uint32
// Ctx pool
pool sync.Pool
// Fasthttp server
server *fasthttp.Server
// App config
config Config
// Converts string to a byte slice
getBytes func(s string) (b []byte)
// Converts byte slice to a string
getString func(b []byte) string
// Hooks
hooks *Hooks
// Latest route & group
latestRoute *Route
// TLS handler
tlsHandler *TLSHandler
// Mount fields
mountFields *mountFields
// Indicates if the value was explicitly configured
configured Config
}
接下来从New函数看下去,主要还是一个初始化配置和申请内存的过程
go// New 创建一个新的 Fiber 命名实例。
//
// app := fiber.New()
//
// 你可以通过传递一个 Config 结构体来传递可选的配置选项:
//
// app := fiber.New(fiber.Config{
// Prefork: true,
// ServerHeader: "Fiber",
// })
func New(config ...Config) *App {
// 创建一个新的应用
app := &App{
// 创建 Ctx 池
pool: sync.Pool{
New: func() interface{} {
return new(Ctx)
},
},
// 创建配置
config: Config{},
getBytes: utils.UnsafeBytes,
getString: utils.UnsafeString,
latestRoute: &Route{},
}
// 定义钩子
app.hooks = newHooks(app)
// 定义挂载字段
app.mountFields = newMountFields(app)
// 如果提供了配置,则覆盖默认配置
if len(config) > 0 {
app.config = config[0]
}
// 在设置默认值之前初始化配置
app.configured = app.config
if app.config.ETag {
if !IsChild() {
log.Warn("Config.ETag 自 v2.0.6 起已弃用,请使用 'middleware/etag'。")
}
}
// 覆盖默认值
if app.config.BodyLimit == 0 {
app.config.BodyLimit = DefaultBodyLimit
}
if app.config.Concurrency <= 0 {
app.config.Concurrency = DefaultConcurrency
}
if app.config.ReadBufferSize <= 0 {
app.config.ReadBufferSize = DefaultReadBufferSize
}
if app.config.WriteBufferSize <= 0 {
app.config.WriteBufferSize = DefaultWriteBufferSize
}
if app.config.CompressedFileSuffix == "" {
app.config.CompressedFileSuffix = DefaultCompressedFileSuffix
}
if app.config.Immutable {
app.getBytes, app.getString = getBytesImmutable, getStringImmutable
}
if app.config.ErrorHandler == nil {
app.config.ErrorHandler = DefaultErrorHandler
}
if app.config.JSONEncoder == nil {
app.config.JSONEncoder = json.Marshal
}
if app.config.JSONDecoder == nil {
app.config.JSONDecoder = json.Unmarshal
}
if app.config.XMLEncoder == nil {
app.config.XMLEncoder = xml.Marshal
}
if app.config.Network == "" {
app.config.Network = NetworkTCP4
}
if len(app.config.RequestMethods) == 0 {
app.config.RequestMethods = DefaultMethods
}
app.config.trustedProxiesMap = make(map[string]struct{}, len(app.config.TrustedProxies))
for _, ipAddress := range app.config.TrustedProxies {
app.handleTrustedProxy(ipAddress)
}
// 创建路由堆栈
app.stack = make([][]*Route, len(app.config.RequestMethods))
app.treeStack = make([]map[string][]*Route, len(app.config.RequestMethods))
// 覆盖颜色
app.config.ColorScheme = defaultColors(app.config.ColorScheme)
// 初始化应用
app.init()
// 返回应用
return app
}
大概过一眼fiber.Config有哪些配置项,不用记,有个印象就好
go// Config is a struct holding the server settings.
type Config struct {
// When set to true, this will spawn multiple Go processes listening on the same port.
//
// Default: false
Prefork bool `json:"prefork"`
// Enables the "Server: value" HTTP header.
//
// Default: ""
ServerHeader string `json:"server_header"`
// When set to true, the router treats "/foo" and "/foo/" as different.
// By default this is disabled and both "/foo" and "/foo/" will execute the same handler.
//
// Default: false
StrictRouting bool `json:"strict_routing"`
// When set to true, enables case sensitive routing.
// E.g. "/FoO" and "/foo" are treated as different routes.
// By default this is disabled and both "/FoO" and "/foo" will execute the same handler.
//
// Default: false
CaseSensitive bool `json:"case_sensitive"`
// When set to true, this relinquishes the 0-allocation promise in certain
// cases in order to access the handler values (e.g. request bodies) in an
// immutable fashion so that these values are available even if you return
// from handler.
//
// Default: false
Immutable bool `json:"immutable"`
// When set to true, converts all encoded characters in the route back
// before setting the path for the context, so that the routing,
// the returning of the current url from the context `ctx.Path()`
// and the parameters `ctx.Params(%key%)` with decoded characters will work
//
// Default: false
UnescapePath bool `json:"unescape_path"`
// Enable or disable ETag header generation, since both weak and strong etags are generated
// using the same hashing method (CRC-32). Weak ETags are the default when enabled.
//
// Default: false
ETag bool `json:"etag"`
// Max body size that the server accepts.
// -1 will decline any body size
//
// Default: 4 * 1024 * 1024
BodyLimit int `json:"body_limit"`
// Maximum number of concurrent connections.
//
// Default: 256 * 1024
Concurrency int `json:"concurrency"`
// Views is the interface that wraps the Render function.
//
// Default: nil
Views Views `json:"-"`
// Views Layout is the global layout for all template render until override on Render function.
//
// Default: ""
ViewsLayout string `json:"views_layout"`
// PassLocalsToViews Enables passing of the locals set on a fiber.Ctx to the template engine
//
// Default: false
PassLocalsToViews bool `json:"pass_locals_to_views"`
// The amount of time allowed to read the full request including body.
// It is reset after the request handler has returned.
// The connection's read deadline is reset when the connection opens.
//
// Default: unlimited
ReadTimeout time.Duration `json:"read_timeout"`
// The maximum duration before timing out writes of the response.
// It is reset after the request handler has returned.
//
// Default: unlimited
WriteTimeout time.Duration `json:"write_timeout"`
// The maximum amount of time to wait for the next request when keep-alive is enabled.
// If IdleTimeout is zero, the value of ReadTimeout is used.
//
// Default: unlimited
IdleTimeout time.Duration `json:"idle_timeout"`
// Per-connection buffer size for requests' reading.
// This also limits the maximum header size.
// Increase this buffer if your clients send multi-KB RequestURIs
// and/or multi-KB headers (for example, BIG cookies).
//
// Default: 4096
ReadBufferSize int `json:"read_buffer_size"`
// Per-connection buffer size for responses' writing.
//
// Default: 4096
WriteBufferSize int `json:"write_buffer_size"`
// CompressedFileSuffix adds suffix to the original file name and
// tries saving the resulting compressed file under the new file name.
//
// Default: ".fiber.gz"
CompressedFileSuffix string `json:"compressed_file_suffix"`
// ProxyHeader will enable c.IP() to return the value of the given header key
// By default c.IP() will return the Remote IP from the TCP connection
// This property can be useful if you are behind a load balancer: X-Forwarded-*
// NOTE: headers are easily spoofed and the detected IP addresses are unreliable.
//
// Default: ""
ProxyHeader string `json:"proxy_header"`
// GETOnly rejects all non-GET requests if set to true.
// This option is useful as anti-DoS protection for servers
// accepting only GET requests. The request size is limited
// by ReadBufferSize if GETOnly is set.
//
// Default: false
GETOnly bool `json:"get_only"`
// ErrorHandler is executed when an error is returned from fiber.Handler.
//
// Default: DefaultErrorHandler
ErrorHandler ErrorHandler `json:"-"`
// When set to true, disables keep-alive connections.
// The server will close incoming connections after sending the first response to client.
//
// Default: false
DisableKeepalive bool `json:"disable_keepalive"`
// When set to true, causes the default date header to be excluded from the response.
//
// Default: false
DisableDefaultDate bool `json:"disable_default_date"`
// When set to true, causes the default Content-Type header to be excluded from the response.
//
// Default: false
DisableDefaultContentType bool `json:"disable_default_content_type"`
// When set to true, disables header normalization.
// By default all header names are normalized: conteNT-tYPE -> Content-Type.
//
// Default: false
DisableHeaderNormalizing bool `json:"disable_header_normalizing"`
// When set to true, it will not print out the «Fiber» ASCII art and listening address.
//
// Default: false
DisableStartupMessage bool `json:"disable_startup_message"`
// This function allows to setup app name for the app
//
// Default: nil
AppName string `json:"app_name"`
// StreamRequestBody enables request body streaming,
// and calls the handler sooner when given body is
// larger then the current limit.
StreamRequestBody bool
// Will not pre parse Multipart Form data if set to true.
//
// This option is useful for servers that desire to treat
// multipart form data as a binary blob, or choose when to parse the data.
//
// Server pre parses multipart form data by default.
DisablePreParseMultipartForm bool
// Aggressively reduces memory usage at the cost of higher CPU usage
// if set to true.
//
// Try enabling this option only if the server consumes too much memory
// serving mostly idle keep-alive connections. This may reduce memory
// usage by more than 50%.
//
// Default: false
ReduceMemoryUsage bool `json:"reduce_memory_usage"`
// FEATURE: v2.3.x
// The router executes the same handler by default if StrictRouting or CaseSensitive is disabled.
// Enabling RedirectFixedPath will change this behavior into a client redirect to the original route path.
// Using the status code 301 for GET requests and 308 for all other request methods.
//
// Default: false
// RedirectFixedPath bool
// When set by an external client of Fiber it will use the provided implementation of a
// JSONMarshal
//
// Allowing for flexibility in using another json library for encoding
// Default: json.Marshal
JSONEncoder utils.JSONMarshal `json:"-"`
// When set by an external client of Fiber it will use the provided implementation of a
// JSONUnmarshal
//
// Allowing for flexibility in using another json library for decoding
// Default: json.Unmarshal
JSONDecoder utils.JSONUnmarshal `json:"-"`
// XMLEncoder set by an external client of Fiber it will use the provided implementation of a
// XMLMarshal
//
// Allowing for flexibility in using another XML library for encoding
// Default: xml.Marshal
XMLEncoder utils.XMLMarshal `json:"-"`
// Known networks are "tcp", "tcp4" (IPv4-only), "tcp6" (IPv6-only)
// WARNING: When prefork is set to true, only "tcp4" and "tcp6" can be chose.
//
// Default: NetworkTCP4
Network string
// If you find yourself behind some sort of proxy, like a load balancer,
// then certain header information may be sent to you using special X-Forwarded-* headers or the Forwarded header.
// For example, the Host HTTP header is usually used to return the requested host.
// But when you’re behind a proxy, the actual host may be stored in an X-Forwarded-Host header.
//
// If you are behind a proxy, you should enable TrustedProxyCheck to prevent header spoofing.
// If you enable EnableTrustedProxyCheck and leave TrustedProxies empty Fiber will skip
// all headers that could be spoofed.
// If request ip in TrustedProxies whitelist then:
// 1. c.Protocol() get value from X-Forwarded-Proto, X-Forwarded-Protocol, X-Forwarded-Ssl or X-Url-Scheme header
// 2. c.IP() get value from ProxyHeader header.
// 3. c.Hostname() get value from X-Forwarded-Host header
// But if request ip NOT in Trusted Proxies whitelist then:
// 1. c.Protocol() WON't get value from X-Forwarded-Proto, X-Forwarded-Protocol, X-Forwarded-Ssl or X-Url-Scheme header,
// will return https in case when tls connection is handled by the app, of http otherwise
// 2. c.IP() WON'T get value from ProxyHeader header, will return RemoteIP() from fasthttp context
// 3. c.Hostname() WON'T get value from X-Forwarded-Host header, fasthttp.Request.URI().Host()
// will be used to get the hostname.
//
// Default: false
EnableTrustedProxyCheck bool `json:"enable_trusted_proxy_check"`
// Read EnableTrustedProxyCheck doc.
//
// Default: []string
TrustedProxies []string `json:"trusted_proxies"`
trustedProxiesMap map[string]struct{}
trustedProxyRanges []*net.IPNet
// If set to true, c.IP() and c.IPs() will validate IP addresses before returning them.
// Also, c.IP() will return only the first valid IP rather than just the raw header
// WARNING: this has a performance cost associated with it.
//
// Default: false
EnableIPValidation bool `json:"enable_ip_validation"`
// If set to true, will print all routes with their method, path and handler.
// Default: false
EnablePrintRoutes bool `json:"enable_print_routes"`
// You can define custom color scheme. They'll be used for startup message, route list and some middlewares.
//
// Optional. Default: DefaultColors
ColorScheme Colors `json:"color_scheme"`
// RequestMethods provides customizibility for HTTP methods. You can add/remove methods as you wish.
//
// Optional. Default: DefaultMethods
RequestMethods []string
// EnableSplittingOnParsers splits the query/body/header parameters by comma when it's true.
// For example, you can use it to parse multiple values from a query parameter like this:
// /api?foo=bar,baz == foo[]=bar&foo[]=baz
//
// Optional. Default: false
EnableSplittingOnParsers bool `json:"enable_splitting_on_parsers"`
}
Prefork:
bool
true
时,将创建多个 Go 进程监听同一端口。false
ServerHeader:
string
""
StrictRouting:
bool
true
时,路由器将 /foo
和 /foo/
视为不同。false
CaseSensitive:
bool
true
时,启用区分大小写的路由。false
Immutable:
bool
true
时,以不可变的方式访问处理程序中的值。false
UnescapePath:
bool
true
时,将所有编码字符转换回原始字符。false
ETag:
bool
false
BodyLimit:
int
4 * 1024 * 1024
Concurrency:
int
256 * 1024
Views:
Views
Render
函数。nil
ViewsLayout:
string
""
PassLocalsToViews:
bool
false
ReadTimeout:
time.Duration
WriteTimeout:
time.Duration
IdleTimeout:
time.Duration
ReadBufferSize:
int
4096
WriteBufferSize:
int
4096
CompressedFileSuffix:
string
".fiber.gz"
ProxyHeader:
string
c.IP()
返回代理头的值。""
GETOnly:
bool
false
ErrorHandler:
ErrorHandler
fiber.Handler
返回的错误。DefaultErrorHandler
DisableKeepalive:
bool
false
DisableDefaultDate:
bool
false
DisableDefaultContentType:
bool
false
DisableHeaderNormalizing:
bool
false
DisableStartupMessage:
bool
false
AppName:
string
nil
StreamRequestBody:
bool
false
DisablePreParseMultipartForm:
bool
false
ReduceMemoryUsage:
bool
false
JSONEncoder:
utils.JSONMarshal
json.Marshal
JSONDecoder:
utils.JSONUnmarshal
json.Unmarshal
XMLEncoder:
utils.XMLMarshal
xml.Marshal
Network:
string
NetworkTCP4
EnableTrustedProxyCheck:
bool
false
TrustedProxies:
[]string
[]string
EnableIPValidation:
bool
false
EnablePrintRoutes:
bool
false
ColorScheme:
Colors
DefaultColors
RequestMethods:
[]string
DefaultMethods
EnableSplittingOnParsers:
bool
false
接下来是一些常量
go// 默认配置值
const (
DefaultBodyLimit = 4 * 1024 * 1024 // 默认请求体大小限制
DefaultConcurrency = 256 * 1024 // 默认并发连接数
DefaultReadBufferSize = 4096 // 默认读取缓冲区大小
DefaultWriteBufferSize = 4096 // 默认写入缓冲区大小
DefaultCompressedFileSuffix = ".fiber.gz" // 默认压缩文件后缀
)
// 默认启用的 HTTP 方法
var DefaultMethods = []string{
MethodGet, // GET 方法
MethodHead, // HEAD 方法
MethodPost, // POST 方法
MethodPut, // PUT 方法
MethodDelete, // DELETE 方法
MethodConnect, // CONNECT 方法
MethodOptions, // OPTIONS 方法
MethodTrace, // TRACE 方法
MethodPatch, // PATCH 方法
}
默认的ErrorHnadler,他会处理所有Error
go// DefaultErrorHandler that process return errors from handlers
func DefaultErrorHandler(c *Ctx, err error) error {
code := StatusInternalServerError
var e *Error
if errors.As(err, &e) {
code = e.Code
}
c.Set(HeaderContentType, MIMETextPlainCharsetUTF8)
return c.Status(code).SendString(err.Error())
}
本文作者:yowayimono
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!