core

package module
v3.1.19 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 19, 2026 License: MIT Imports: 83 Imported by: 0

README

Core Web Framework v3 - 完整帮助文档

概述

Core 是一个用于快速开发企业级 Go 应用程序的 Web 框架,包括 RESTful API、Web 应用和后端服务。它受到 Tornado、Sinatra 和 Koa (Node.js) 的启发,并具有一些 Go 特有的功能,如接口和结构体嵌入。

主要特性
  • 自动路由注册 - 无需手动配置路由
  • Koa 风格开发 - 类似 Node.js Koa 框架的中间件链式调用
  • 轻量级框架 - 简单易用,性能高效
  • 多数据库支持 - MySQL、PostgreSQL、SQLite、ClickHouse
  • 内置验证器 - 基于 go-playground/validator
  • JSON/XML 支持 - 内置 JSON 和 XML 响应处理
  • 文件上传 - 支持单文件和多文件上传
  • WebSocket 支持 - 内置 WebSocket 处理
  • 模板引擎 - 支持 HTML 模板渲染
  • Fetch 客户端 - 独立 fetch 包,支持 API 调用、公共/单次 Header、Cookie、请求/响应 Hook
  • Redis Cache - 独立 cache 包,支持 DB fallback、自动回填、singleflight 防击穿、空值缓存
  • 中间件系统 - 灵活的中间件扩展机制
  • ai-context - AI 的工作流程指南
  • skills - 模式库和示例

参考文档:

  • ./AI_CONTEXT.md - Core 框架完整上下文
  • ./skills/ - 场景化开发模板

快速开始

安装
go get github.com/xs23933/core/v3
最小示例
package main

import "github.com/xs23933/core/v3"

type Handler struct {
    core.Handler
}

func (Handler) Get(c core.Ctx) {
    c.SendString("Hello, World!")
}

func init() {
    core.RegHandle(new(Handler))
}

func main() {
    app := core.New()
    app.Listen(":8080")
}

项目结构

project/
├── cmd/               # 命令行目录
│   └── main.go        # 主入口文件
├── config.yaml        # 配置文件
├── views/             # 模板文件
├── static/            # 静态文件
├── internal/          # 内部目录
    ├── handler/       # 处理器目录
    │   └── handler.go # 业务逻辑
    ├── models/        # 数据模型
    │   └── models.go  # 数据库模型定义
    ├── middleware/    # 中间件
    ├── service/       # (业务逻辑:事务操作,调用 dao/model)
    └── dao/           # (数据访问:复杂查询封装)

配置

config.yaml 示例
debug: true # 调试模式
network: tcp4 # 网络协议
listen: 8080 # 监听端口
prefork: false # 是否启用 prefork 模式
log: /var/log/myapp/app.log # 可选:日志文件路径
log_rotate:
  - size: 300M # 文件达到 300MB 后切割
  - daily # 每日切割
  - rotate: 30 # 保留最近 30 天的切割日志
  - compress # 切割后的日志 gzip 压缩
  - delaycompress: 24h # 延迟压缩,需配合 compress
  - missingok # 日志文件不存在时不报错
  - notifempty # 空日志不切割
  - copytruncate # 复制后截断原文件,不替换当前文件句柄

# RESTful 响应格式配置
restful:
  data: data # 数据字段名
  status: success # 状态字段名
  message: msg # 消息字段名

# 数据库配置
database:
  type: sqlite3 # 数据库类型: mysql, pg, sqlite3, clickhouse
  dsn: dat # 数据库连接字符串
  # MySQL 示例: user:password@tcp(localhost:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local
  # PostgreSQL 示例: host=localhost user=postgres password=postgres dbname=test port=5432 sslmode=disable

核心概念

1. 应用 (Core)

应用是框架的核心,负责管理路由、中间件和服务器。

// 创建应用
app := core.New(core.LoadConfigFile("config.yaml"))

// 启动服务器
app.Listen()
2. 上下文 (Ctx)

上下文对象封装了 HTTP 请求和响应,提供了丰富的操作方法。

func (Handler) Get(c core.Ctx) {
    // 获取请求信息
    method := c.Method()      // 请求方法
    path := c.Path()          // 请求路径
    ip := c.RemoteIP()        // 客户端 IP

    // 获取参数
    id := c.Params("id")              // 路径参数
    name := c.Query("name")           // 查询参数
    age := c.QueryInt("age", 18)      // 查询参数转int

    // 获取表单数据
    email := c.FormValue("email")

    // 获取请求头
    token := c.GetHeader("Authorization")

    // 设置响应头
    c.SetHeader("Content-Type", "application/json")

    // 发送响应
    c.SendString("Hello")
    c.JSON(map[string]any{"code": 200, "msg": "success"})
    c.SendStatus(404, "Not Found")
}
3. 处理器 (Handler)

处理器是业务逻辑的载体,通过嵌入 core.Handler 来获得框架功能。

type UserHandler struct {
    core.Handler
}

// Init 定义Prefix 此Handler 下都加上了 /users group
func (UserHandler) Init() {
	core.Prefix("/users")
}

// GET /users
func (UserHandler) Get(c core.Ctx) {
    users, err := models.GetUsers()
    c.ToJSON(users, err)
}

// POST /users
func (UserHandler) Post(c core.Ctx) {
    var user models.User
    if err := c.ReadBody(&user); err != nil {
        c.ToJSON(nil, err)
        return
    }
    c.ToJSON(user, user.Save())
}

// GET /users/:id
func (UserHandler) GetByID(c core.Ctx) {
    id, err := c.ParamsUid("id")
    if err != nil {
        c.ToJSON(nil, err)
        return
    }
    user, err := models.GetUserByID(id)
    c.ToJSON(user, err)
}

// 自动注册路由
func init() {
    core.RegHandle(new(UserHandler))
}
4. 路由系统

框架支持自动路由注册,基于方法名和注释生成路由。

路由规则
关键字 路由规则 结果
Param 参数关键词 :param
Params 参数关键词 :params?
_id 下划线 /:id
By 参数关键字 /:
__ 中横线 -
__dot__ .

Params 是可选关键词 即:params?

  • GetGET /
  • GetParamGET /:param
  • GetParamsGET /:params?
  • GetByIDGET /:id
  • GetDetailParamGET /detail/:param
  • PostUserPOST /user
  • PutUserParamPUT /user/:param
  • GetUserByIDGET /user/:id
  • GetUser__CreateGET /user-create
  • GetUser__dot__HtmlGET /user.html
路由注释
// GetUser 获取用户信息
// get /user/:param
// @id: uid.UID 用户ID
func (Handler) GetUserParam(c core.Ctx) {
    id, err := c.ParamsUid("param")
	c.ToJSON(nil, err)
}
5. 数据模型

框架集成了 GORM,提供了便捷的数据库操作。

package models

import "github.com/xs23933/core/v3"

type User struct {
    core.Model
    Username string `json:"username" gorm:"size:32;uniqueIndex"`
    Email    string `json:"email" gorm:"size:128;uniqueIndex"`
    Password string `json:"-" gorm:"size:96"`
    Age      int    `json:"age" gorm:"default:18"`
}

// 创建用户
func (u *User) Create() error {
    return db.Create(u).Error
}

// 根据ID查询用户
func GetUserByID(id uid.UID) (user User, err error) {
    err = db.First(&user, "id = ?", id).Error
    return
}

// 分页查询用户
func GetUsers(page, size int) (users []User, total int64, err error) {
    err = db.Model(&User{}).Count(&total).Error
    if err != nil {
        return
    }
    offset := (page - 1) * size
    err = db.Offset(offset).Limit(size).Find(&users).Error
    return
}


var db *core.DB
// 初始化数据库
func InitDB() {
    db := core.Conn()
    db.AutoMigrate(&User{})
}
6. 中间件

框架支持灵活的中间件系统。

// 自定义中间件
func AuthMiddleware(next core.HandlerFunc) core.HandlerFunc {
    return func(c core.Ctx) error {
        token := c.GetHeader("Authorization")
        if token == "" {
            return c.SendStatus(401, "Unauthorized")
        }
        // 验证 token
        // ...
        return next(c)
    }
}

// 使用中间件
app.Use(AuthMiddleware)

// 路由级中间件
app.GET("/admin", AdminHandler, AuthMiddleware)
内置中间件
import (
    "github.com/xs23933/core/v3/middleware/requestid"
    "github.com/xs23933/core/v3/middleware/cors"
    "github.com/xs23933/core/v3/middleware/logger"
    "github.com/xs23933/core/v3/middleware/recover"
)

app.Use(requestid.New())  // 请求ID
app.Use(cors.New(app))    // CORS 支持
app.Use(logger.New())     // 请求日志
app.Use(recover.New())    // 异常恢复
7. 验证器

框架集成了 go-playground/validator,支持结构体验证。

type LoginForm struct {
    Username string `json:"username" validate:"required,min=3,max=32"`
    Password string `json:"password" validate:"required,min=6,max=128"`
    Email    string `json:"email" validate:"omitempty,email"`
}

func (Handler) Login(c core.Ctx) {
    var form LoginForm
    if err := c.ReadBody(&form); err != nil {
        c.ToJSON(nil, err)
        return
    }

    // 自动验证
    if err := c.Validate(&form); err != nil {
        c.ToJSON(nil, err)
        return
    }

    // 业务逻辑
    // ...
}
8. 文件上传
// 单文件上传
func (Handler) Upload(c core.Ctx) {
    file, err := c.FormFile("file")
    if err != nil {
        c.ToJSON(nil, err)
        return
    }

    // 保存文件
    relpath, abspath, err := c.SaveFile("file", "./uploads")
    if err != nil {
        c.ToJSON(nil, err)
        return
    }

    c.ToJSON(map[string]string{
        "filename": file.Filename,
        "path":     relpath,
        "size":     fmt.Sprintf("%d", file.Size),
    })
}

// 多文件上传
func (Handler) UploadMultiple(c core.Ctx) {
    files, err := c.SaveFiles("files", "./uploads")
    if err != nil {
        c.ToJSON(nil, err)
        return
    }

    c.ToJSON(files)
}
9. WebSocket 支持
import "github.com/xs23933/core/v3/websocket"


func main() {
	app := core.New()
	app.GET("/ws", websocket.New().
		OnConnect(func(c *websocket.Conn) {
			c.Send([]byte("Welcome to WebSocket"))
		}).
		OnMessage(
			func(c *websocket.Conn, mt websocket.MessageType, b []byte) {
				c.SendWithType(mt, b) //reply
                core.Info("Received message: %s", string(b))
			},
		).OnClose(func(c *websocket.Conn) {
		println("Connection closed")
	}).Handler())
	app.Run()
}

10. 模板渲染
import (
    "github.com/xs23933/core/v3/middleware/view"
    "github.com/xs23933/core/v3/middleware/view/html"
)

// 配置模板引擎
var viewEngine view.IEngine = html.NewHtmlView("./views", ".html", app.Debug)
app.Use(viewEngine)

// 渲染模板
func (Handler) Index(c core.Ctx) {
    c.Render("index", core.Map{
        "title": "首页",
        "users": []User{...},
    })
}

gRPC、etcd 与网关

Core 支持同时运行 HTTP 与 gRPC,并通过 etcd 做服务注册、服务发现和网关动态路由。推荐把链路拆成三类程序理解:

  1. 业务服务:注册 protobuf 生成的 gRPC service,启动 gRPC,必要时注册到 etcd。
  2. 内部客户端:通过 app.GrpcClient("service-name") 按服务名发现并调用 gRPC。
  3. 网关服务:监听 etcd 服务变化,通过 gRPC reflection 自动发现方法并生成 HTTP 路由。
1. gRPC 服务

服务端必须先注册 gRPC service,再启动应用。只需要 gRPC 时使用 EnableGRPC;需要被网关发现时使用 EnableEtcdRegistry,它会自动创建/复用 gRPC server、注册服务到 etcd,并开启 gRPC reflection。

package main

import (
    "context"

    "github.com/xs23933/core/v3"
    "google.golang.org/grpc"

    pb "your_project/proto/user/v1"
)

type UserService struct {
    pb.UnimplementedUserServiceServer
}

func (s *UserService) GetProfile(ctx context.Context, req *pb.GetProfileRequest) (*pb.User, error) {
    return &pb.User{Id: req.Id, Name: "tom"}, nil
}

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

    app.RegisterGRPCService(func(s *grpc.Server) {
        pb.RegisterUserServiceServer(s, &UserService{})
    })

    app.EnableGRPC(":9001")

    if err := app.Listen(":8080"); err != nil {
        panic(err)
    }
}

HTTP 和 gRPC 使用不同端口时,Listen(":8080") 负责 HTTP,EnableGRPC(":9001") 负责 gRPC。

如果希望 HTTP/1 和 gRPC 共用端口,可以让 EnableGRPC 使用和 Listen 相同的地址。框架会根据 HTTP/2 与 Content-Type: application/grpc 自动分流。

app.RegisterGRPCService(func(s *grpc.Server) {
    pb.RegisterUserServiceServer(s, &UserService{})
})
app.EnableGRPC(":8080")
app.Listen(":8080")

需要注册到 etcd 并提供给网关时:

app := core.New(core.LoadConfigFile("config.yaml"))

app.RegisterGRPCService(func(s *grpc.Server) {
    pb.RegisterUserServiceServer(s, &UserService{})
})

if err := app.EnableEtcdRegistry(nil); err != nil {
    panic(err)
}

if err := app.Listen(":8080"); err != nil {
    panic(err)
}
2. etcd 配置

EnableEtcdRegistry(nil) 会读取 etcd 配置。服务端最少需要配置 endpoints、service name 和暴露给其它进程访问的 service addr。

etcd:
  endpoints:
    - 127.0.0.1:2379
  dial_timeout: 5
  service_name: user-service
  service_addr: 127.0.0.1:8080
  service_id: user-service-1
  ttl: 10
  version: 1.0.0

也可以直接传 etcd.Options,适合测试或多环境注入:

if err := app.EnableEtcdRegistry(&etcd.Options{
    Endpoints:   []string{"127.0.0.1:2379"},
    ServiceName: "user-service",
    ServiceAddr: "127.0.0.1:8080",
    ServiceID:   "user-service-1",
    TTL:         10,
    Version:     "1.0.0",
    Metadata: map[string]string{
        "env": "dev",
    },
}); err != nil {
    panic(err)
}

注意:

  • service_addr 必须是客户端和网关能访问到的地址,不一定等于本机监听地址。
  • 使用网关自动注册路由时,优先用 EnableEtcdRegistry,因为它会自动开启 reflection。
  • RegisterGRPCService 要在 ListenRun 前调用。
3. gRPC 客户端

内部服务调用优先使用 GrpcClient,它会通过 etcd resolver 按服务名连接后端实例。

app := core.New(core.LoadConfigFile("config.yaml"))

conn, err := app.GrpcClient("user-service")
if err != nil {
    panic(err)
}
defer conn.Close()

client := pb.NewUserServiceClient(conn)

如果依赖 GrpcClient 自动初始化 discovery,客户端读取 etcd.endpointsetcd.dialTimeout;网关配置读取 etcd.dial_timeout

如果启动阶段必须拿到连接,可以用 MustGrpcClient;它失败会 panic,适合 main 函数初始化,不适合请求处理链路。

conn := app.MustGrpcClient("user-service")
client := pb.NewUserServiceClient(conn)
4. 网关启动

网关服务只需要连接 etcd 并启用 gateway。启动时会读取已有服务实例,之后继续 watch 服务上下线和路由变化。业务服务需要使用 EnableEtcdRegistry 注册并开启 reflection,网关才能自动发现方法。

package main

import (
    "log"

    "github.com/xs23933/core/v3"
    "github.com/xs23933/core/v3/gateway"
)

func main() {
    app := core.New(core.LoadConfigFile("config.yaml"))

    if err := app.EnableEtcdDiscovery(nil); err != nil {
        log.Fatal("启用 etcd 服务发现失败:", err)
    }

    _, err := gateway.NewEtcdGateway(app)
    if err != nil {
        panic(err)
    }

    app.Listen(":8080")
}

网关内置本地管理接口,仅允许 loopback 地址访问:

方法 路径 说明
GET /admin/gateway/routes 路由列表
GET /admin/gateway/routes/:id 路由详情
POST /admin/gateway/routes 创建路由
PUT /admin/gateway/routes/:id 更新或禁用路由
DELETE /admin/gateway/routes/:id 删除路由
5. 自动注册路由规则

网关通过 gRPC reflection 读取服务方法,并按方法名前缀自动生成 HTTP 路由。

gRPC 方法名 HTTP 方法 HTTP 路径示例
PostLogin POST /v1/auth/user/login
GetProfile GET /v1/auth/user/profile
PutProfile PUT /v1/auth/user/profile
DeleteSession DELETE /v1/auth/user/session
GetUserById GET /v1/auth/user/:id
GetOrderByUserId GET /v1/order/order/:user/id

转换逻辑:

  • proto package v1.auth 转为路径前缀 /v1/auth
  • service v1.auth.UserService 转为 /user
  • 方法前缀 Post/Get/Put/Delete 转为 HTTP method
  • 方法名剩余部分按 CamelCase 拆成路径
  • By 转为路径参数标记 :
  • 缩写建议使用 Id 而不是 ID,避免被拆成 /i/d

例如:

syntax = "proto3";

package v1.auth;

service UserService {
  rpc PostLogin(LoginRequest) returns (LoginResponse);
  rpc GetUserById(GetUserRequest) returns (User);
}

自动生成:

POST /v1/auth/user/login      -> /v1.auth.UserService/PostLogin
GET  /v1/auth/user/:id        -> /v1.auth.UserService/GetUserById

当服务 reflection 中的方法减少,或 etcd 中的路由被删除/禁用时,网关会注销旧 HTTP 路由。

6. 手动配置网关路由

除了自动注册,也可以通过管理接口写入路由配置。

POST http://127.0.0.1:8080/admin/gateway/routes
Content-Type: application/json

{
  "method": "POST",
  "path": "/api/login",
  "service_name": "user-service",
  "grpc_method": "/v1.auth.UserService/PostLogin",
  "description": "manual login route"
}

禁用路由:

PUT http://127.0.0.1:8080/admin/gateway/routes/{route_id}
Content-Type: application/json

{
  "method": "POST",
  "path": "/api/login",
  "service_name": "user-service",
  "grpc_method": "/v1.auth.UserService/PostLogin",
  "enabled": false
}
7. HTTP 到 gRPC 的请求映射

网关会把 HTTP 路径参数、query 参数和 JSON body 合并为一个 JSON 对象,然后按 reflection 中的请求 message 反序列化。

GET /v1/auth/user/123?expand=true
Authorization: Bearer token
X-Request-Id: req-1

会转成类似:

{
  "id": "123",
  "expand": "true"
}

默认透传的 metadata:

  • authorization
  • x-request-id
  • x-user-id
  • Ctx.Vars() 中的本地变量 用于前置 middleware 处理后的后传参数 例如 jwt处理的: Ctx.Set("user_id", "123")
8. Demo 目录

仓库内置了几个最小 demo:

目录 说明 运行命令
example/restful REST、模板、中间件、自动路由 go run ./example/restful
example/work 配置文件、数据库模型、分页查询 go run ./example/work
example/websocket WebSocket echo 示例 go run ./example/websocket

REST demo 中同时展示了手写路由和自动路由:

app.GET("/", func(c core.Ctx) {
    c.SendString("what happend")
})

type handler struct {
    core.Handler
}

func (handler) GetHello(c core.Ctx) {
    c.SendString("ok")
}

func (handler) GetUser_id(c core.Ctx) {
    c.SendString("id is %s", c.Params("id"))
}

func init() {
    core.RegHandle(&handler{})
}

生成的自动路由:

GET /hello
GET /user/:id

高级功能

1. 数据库事务
func CreateUserWithProfile(db *core.DB, user User, profile Profile) error {
    return db.Transaction(func(tx *core.DB) error {
        if err := tx.Create(&user).Error; err != nil {
            return err
        }

        profile.UserID = user.ID
        if err := tx.Create(&profile).Error; err != nil {
            return err
        }

        return nil
    })
}
2. 连接多个数据库
database:
  default:
    type: mysql
    dsn: user:pass@tcp(localhost:3306)/main
  log:
    type: clickhouse
    dsn: tcp://localhost:9000?database=logs
// 使用默认数据库
db := core.Conn()

// 使用指定数据库
logDB := core.Conn("log")
3. 查询构建器
// 链式查询
var users []User
err := core.Conn().
    Select("id, username, email").
    Where("age > ?", 18).
    Where("status = ?", "active").
    Order("created_at DESC").
    Limit(10).
    Offset(0).
    Find(&users).Error

// 原生 SQL
var count int
core.Conn().Raw("SELECT COUNT(*) FROM users WHERE age > ?", 18).Scan(&count)

// 子查询
subQuery := core.Conn().Model(&Order{}).Select("user_id").Where("amount > ?", 1000)
core.Conn().Where("id IN (?)", subQuery).Find(&users)
4. 分页查询:FindPageBy 与 FindNextBy

FindPageByFindNextBy 都会读取 core.Map 中的分页和筛选参数,并可以接收一个已经拼好的 *core.DB 作为基础查询。

常用参数:

参数 说明
p 页码,默认 1
l 每页数量,默认 20
asc 升序字段,如 created_at
desc 降序字段,如 created_at
name 内置 name 模糊查询
field IN IN 查询,如 status IN: []int{}
field > 比较查询,支持 > < >= <=
field* 包含匹配,等价于 %value%
^field 前缀匹配,等价于 value%
field$ 后缀匹配,等价于 %value

两者区别:

  • FindPageBy:返回 Page[T],包含 total 总数;适合后台管理、需要显示总页数的列表。代价是会执行 count。
  • FindNextBy:返回 NextPage[T],包含 next/prev;通过查询 limit + 1 判断是否还有下一页,不统计总数。适合滚动加载、移动端列表、数据量较大的查询。
FindPageBy:带总数分页
type UsersViewDAO struct {
    db *core.DB
}

func (dao *UsersViewDAO) ListPage(ctx context.Context, whr *core.Map) (core.Page[user.UsersView], error) {
    if _, ok := (*whr)["asc"].(string); !ok {
        if _, ok := (*whr)["desc"].(string); !ok {
            (*whr)["desc"] = "created_at"
        }
    }

    tx := dao.db.WithContext(ctx).
        Model(&user.UsersView{}).
        Select("users_profiles.*, users.status").
        Joins("JOIN users ON users.id = users_profiles.user_id").
        Joins("JOIN users_identities ON users_profiles.user_id = users_identities.user_id")

    res := make([]user.UsersView, 0)
    return core.FindPageBy(whr, &res, tx)
}

返回结构:

{
  "p": 1,
  "l": 20,
  "total": 128,
  "data": []
}
FindNextBy:后推分页

FindNextBy 会多查一条数据判断 next。如果 ret.Next == true,通常需要把多查出来的最后一条裁掉再返回。

func (dao *UsersViewDAO) ListNext(ctx context.Context, whr *core.Map) (core.NextPage[user.UsersView], error) {
    if _, ok := (*whr)["asc"].(string); !ok {
        if _, ok := (*whr)["desc"].(string); !ok {
            (*whr)["desc"] = "created_at"
        }
    }

    tx := dao.db.WithContext(ctx).
        Model(&user.UsersView{}).
        Select("users_profiles.*, users.status").
        Joins("JOIN users ON users.id = users_profiles.user_id").
        Joins("JOIN users_identities ON users_profiles.user_id = users_identities.user_id")

    res := make([]user.UsersView, 0)
    ret, err := core.FindNextBy(whr, &res, tx)
    if ret.Next {
        ret.Data = res[:len(res)-1]
    }
    return ret, err
}

返回结构:

{
  "p": 1,
  "l": 20,
  "next": true,
  "prev": false,
  "data": []
}
同一个 DAO 根据参数切换分页模式
func (dao *UsersViewDAO) List(ctx context.Context, whr *core.Map, page bool) (any, error) {
    _, asc := (*whr)["asc"].(string)
    _, desc := (*whr)["desc"].(string)
    if !asc && !desc {
        (*whr)["desc"] = "created_at"
    }
    if tp := whr.GetString("type"); tp != "" {
        (*whr)["type"] = constants.ParseLoginType(tp)
    }

    tx := dao.db.WithContext(ctx).
        Model(&user.UsersView{}).
        Select("users_profiles.*, users.status").
        Joins("JOIN users ON users.id = users_profiles.user_id").
        Joins("JOIN users_identities ON users_profiles.user_id = users_identities.user_id")

    res := make([]user.UsersView, 0)

    if page {
        return core.FindPageBy(whr, &res, tx)
    }

    ret, err := core.FindNextBy(whr, &res, tx)
    if ret.Next {
        ret.Data = res[:len(res)-1]
    }
    return ret, err
}
5. 事件钩子
type User struct {
    core.Model
    Username string
    Password string
}

// 保存前钩子 具体可参照 gorm官方文档
func (u *User) BeforeSave(tx *core.DB) error {
    if u.Password != "" {
        hashed, err := bcrypt.GenerateFromPassword([]byte(u.Password), bcrypt.DefaultCost)
        if err != nil {
            return err
        }
        u.Password = string(hashed)
    }
    return nil
}

// 查询后钩子
func (u *User) AfterFind(tx *core.DB) error {
    u.Password = "" // 隐藏密码字段
    return nil
}

Redis Cache 通用包装器

cache 是独立子包,用于封装“先读缓存,未命中再查 DB,并自动回填缓存”的常见模式。

导入路径:

import "github.com/xs23933/core/v3/cache"

推荐为每类数据创建可复用 cache 实例,把 Redis 连接、前缀、TTL 和空值缓存策略集中配置一次。

type UserVO struct {
    ID   string `json:"id"`
    Name string `json:"name"`
}

var userCache = cache.New(
    core.RConn("cache"),
    cache.Prefix("user:"),
    cache.TTL(10*time.Minute),
    cache.EmptyTTL(time.Minute),
    cache.Jitter(30*time.Second),
    cache.CacheNil(true),
)

func GetUser(ctx context.Context, id string) (UserVO, error) {
    var user UserVO
    err := userCache.Take(ctx, id, &user, func(ctx context.Context) (any, error) {
        return dao.GetUserByID(ctx, id)
    })
    return user, err
}

同一个 cache 实例可以缓存不同类型,类型由 out 指针决定。

var order OrderVO
err := userCache.Take(ctx, "order:"+orderID, &order, func(ctx context.Context) (any, error) {
    return dao.GetOrderByID(ctx, orderID)
})

想保留返回值风格时,用包级泛型 helper。它不要求 New 绑定类型。

user, err := cache.Load[UserVO](userCache, ctx, "user:"+id, func(ctx context.Context) (UserVO, error) {
    return dao.GetUserByID(ctx, id)
})

user, err = cache.Get(ctx, "user:"+id, func(ctx context.Context) (UserVO, error) {
    return dao.GetUserByID(ctx, id)
})

空值缓存用于防止不存在的数据持续打到 DB。默认识别 cache.ErrNotFound,也可以接入项目自己的 not found 错误。

var userCache = cache.New(
    core.RConn("cache"),
    cache.Prefix("user:"),
    cache.CacheNil(true),
    cache.NotFound(func(err error) bool {
        return errors.Is(err, gorm.ErrRecordNotFound)
    }),
)

更新或删除数据后删除缓存:

if err := userCache.Delete(ctx, id); err != nil {
    return err
}

规则:

  • Take / Load 内部使用 singleflight 合并同进程并发 miss,避免缓存击穿。
  • Redis 读失败会降级执行 loader;写缓存失败不会影响返回结果。
  • TTL 可用 Jitter 增加随机抖动,避免大量 key 同时过期。
  • 不要在每次请求中重复 cache.New;应创建可复用实例。

Fetch API 客户端

fetch 是独立子包,用于调用外部 HTTP API。设计接近前端 JavaScript fetch 的使用习惯,但保留 Go 的显式错误处理和结构体 decode。

导入路径:

import "github.com/xs23933/core/v3/fetch"
1. 最简调用

包级快捷方法使用 fetch.Default,适合一次性调用或简单脚本。

type UserVO struct {
    ID   string `json:"id"`
    Name string `json:"name"`
}

var user UserVO
res, err := fetch.Get("https://api.example.com/users/1", &user)
if err != nil {
    return err
}

token := res.Header.Get("X-Token")
_ = token

POST / PUT 带参数时,params 会按类型自动处理:

参数类型 处理方式
nil 不发送 body
[]byte 原始 body
string 字符串 body
其它类型 JSON body,并设置 Content-Type: application/json; charset=utf-8
var out UserVO

_, err := fetch.Post(
    "https://api.example.com/users",
    map[string]any{"name": "tom"},
    &out,
)

_, err = fetch.Put(
    "https://api.example.com/users/1",
    map[string]any{"name": "jerry"},
    &out,
)

_, err = fetch.Delete("https://api.example.com/users/1", nil)
2. 可复用 Client

业务服务中推荐创建可复用 client,统一配置 baseURL、公共 Header、Cookie 和 Hook。

var api = fetch.New("https://api.example.com").
    Header("X-App", "core-service").
    Header("Accept", "application/json").
    UseCookie(true)

func GetUser(ctx context.Context, id string) (UserVO, error) {
    var user UserVO

    res, err := api.DoGet(ctx, "/users/"+id, &user)
    if err != nil {
        return user, err
    }

    refreshedToken := res.Header.Get("X-Token")
    _ = refreshedToken

    return user, nil
}

公共 Header 和单次 Header 分开:

api := fetch.New("https://api.example.com").
    Header("X-App", "core-service") // 每次请求都有

var out UserVO
res, err := api.Post("/users").
    Header("X-Request-ID", "req-123"). // 只对本次请求生效
    JSON(map[string]any{"name": "tom"}).
    Result(context.Background(), &out)
3. 请求前 Hook:签名、鉴权、时间戳

Before 在请求发出前执行,可以读取最终 body 并修改 *http.Request。常用于 hash 签名、认证 Header、请求追踪。

api := fetch.New("https://api.example.com").
    Before(func(ctx context.Context, req *http.Request, body []byte) error {
        sign := core.SHA256HashBytes(body)
        req.Header.Set("X-Sign", sign)
        req.Header.Set("X-Timestamp", strconv.FormatInt(time.Now().Unix(), 10))
        return nil
    })

var out UserVO
_, err := api.DoPost(context.Background(), "/users", map[string]any{"name": "tom"}, &out)
4. 响应后 Hook:解包、解密、统一 decode

After 在响应 body 读取完成后执行,返回值会作为最终 body 继续 decode。适合统一响应格式解包。

type Envelope struct {
    Code int             `json:"code"`
    Msg  string          `json:"msg"`
    Data json.RawMessage `json:"data"`
}

api := fetch.New("https://api.example.com").
    After(func(ctx context.Context, resp *http.Response, body []byte) ([]byte, error) {
        var env Envelope
        if err := json.Unmarshal(body, &env); err != nil {
            return nil, err
        }
        if env.Code != 0 {
            return nil, fmt.Errorf("api error %d: %s", env.Code, env.Msg)
        }
        return env.Data, nil
    })

var user UserVO
_, err := api.DoGet(context.Background(), "/users/1", &user)
5. 获取响应 Header、Status、Body

使用 ResultDoGet/DoPost/DoPut/DoDelete 会返回 *fetch.FetchResult

res, err := api.Get("/session").Result(context.Background(), &out)
if err != nil {
    if ferr, ok := err.(*fetch.FetchError); ok {
        retryToken := ferr.Header.Get("X-Token")
        body := string(ferr.Body)
        _ = retryToken
        _ = body
    }
    return err
}

token := res.Header.Get("X-Token")
status := res.StatusCode
body := res.Body

默认不保存 Cookie,避免隐式状态。需要模拟浏览器会话时显式启用:

api := fetch.New("https://api.example.com").UseCookie(true)

// 禁用并清空 cookie jar
api.UseCookie(false)

错误处理

自定义错误处理
// 全局错误处理
app.ErrorHandler = func(c core.Ctx, err error) {
    if e, ok := err.(*core.HTTPError); ok {
        c.SendStatus(e.Code, e.Message)
        return
    }

    // 记录错误日志
    core.Erro("请求处理失败: %v", err)

    // 生产环境隐藏详细错误
    if app.Debug {
        c.SendStatus(500, err.Error())
    } else {
        c.SendStatus(500, "Internal Server Error")
    }
}

// 业务错误
func (Handler) GetUser(c core.Ctx) {
    user, err := models.GetUserByID(id)
    if err != nil {
        if errors.Is(err, gorm.ErrRecordNotFound) {
            c.SendStatus(404, "用户不存在")
            return
        }
        c.SendStatus(500, "服务器错误")
        return
    }
    c.ToJSON(user)
}

性能优化

1. 连接池配置
database:
  type: mysql
  dsn: user:pass@tcp(localhost:3306)/dbname
  pool:
    max_idle: 10 # 最大空闲连接数
    max_open: 100 # 最大打开连接数
    max_lifetime: 1h # 连接最大生命周期
2. 启用 Prefork 模式
prefork: true # 启用多进程模式,充分利用多核CPU

测试

单元测试
package handler_test

import (
    "testing"
    "github.com/xs23933/core/v3"
)

func TestUserHandler(t *testing.T) {
    app := core.New()

    // 模拟请求
    req := core.TestRequest{
        Method: "GET",
        Path:   "/users/1",
    }

    resp := app.Test(req)

    if resp.StatusCode != 200 {
        t.Errorf("期望状态码 200,得到 %d", resp.StatusCode)
    }
}
集成测试
@baseURL = http://localhost:8080
@contentType = application/json

### 创建用户
POST {{baseURL}}/users
Content-Type: {{contentType}}

{
    "username": "testuser",
    "email": "test@example.com",
    "password": "password123"
}

### 获取用户
GET {{baseURL}}/users/1

### 获取用户列表
GET {{baseURL}}/users?page=1&size=10

部署

1. 编译
go build -o app main.go
2. 使用 Systemd
# /etc/systemd/system/myapp.service
[Unit]
Description=My Core Application
After=network.target

[Service]
Type=simple
User=appuser
WorkingDirectory=/opt/myapp
ExecStart=/opt/myapp/app
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target
3. 使用 Docker
FROM golang:1.24-alpine AS builder

WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN go build -o app main.go

FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /app/app .
COPY --from=builder /app/config.yaml .
EXPOSE 8080
CMD ["./app"]

常见问题

1. 路由不生效

问题: 处理器方法已定义,但路由不生效。

解决方案:

  • 确保处理器嵌入了 core.Handler
  • 确保在 init() 函数中调用 core.RegHandle()
  • 检查方法名是否符合路由规则
  • 查看日志确认路由注册情况
2. 数据库连接失败

问题: 数据库连接失败,返回错误。

解决方案:

  • 检查 config.yaml 中的数据库配置
  • 确认数据库服务是否运行
  • 检查连接字符串格式是否正确
  • 查看数据库日志获取详细错误信息
3. 跨域问题

问题: 前端请求被浏览器阻止,提示跨域错误。

解决方案:

  • 启用 CORS 中间件
  • 配置正确的 CORS 选项
import "github.com/xs23933/core/v3/middleware/cors"

app.Use(cors.New(app, cors.Config{
    AllowOrigins:     "http://localhost:3000",
    AllowMethods:     "GET,POST,PUT,DELETE,OPTIONS",
    AllowHeaders:     "Content-Type,Authorization",
    AllowCredentials: true,
}))
4. 文件上传大小限制

问题: 上传大文件时失败。

解决方案:

  • 调整最大文件大小限制
app := core.New(core.Options{
    "max_body_size": "10MB", // 10MB 限制
})

API 参考

核心方法
Ctx 接口主要方法
方法 说明 示例
Params(key) 获取路径参数 c.Params("id")
Query(key) 获取查询参数 c.Query("name")
FormValue(key) 获取表单值 c.FormValue("email")
ReadBody(out) 读取请求体 c.ReadBody(&user)
Validate(out) 验证结构体 c.Validate(&form)
ToJSON(data, err) 返回 JSON 响应 c.ToJSON(user, nil)
JSON(data) 返回 JSON 响应 c.JSON(user)
Type(ty) 设置响应类型 c.Type("json")
Send(msg) 发送[]byte c.Send([]byte( "Not Found"))
SendString(msg) 发送状String c.SendString("Not Found")
SendStatus(code, msg) 发送状态码 c.SendStatus(404, "Not Found")
SetHeader(key, value) 设置响应头 c.SetHeader("Content-Type", "application/json")
GetHeader(key) 获取请求头 c.GetHeader("Authorization")
FormFile(key) 获取上传文件 c.FormFile("file")
SaveFile(key, dst) 保存上传文件 c.SaveFile("file", "./uploads")
数据库操作
方法 说明 示例
core.DB gorm.DB别名 db *core.DB
core.Conn(name) 获取指定数据库连接 core.Conn("log")
core.Transaction(fn) 执行事务 core.Transaction(func(tx) { ... })
core.Find(out) 查询数据 core.Find(&users)
core.First(out, where) 查询单条数据 core.First(&user, "id = ?", id)
配置选项
选项 类型 默认值 说明
debug bool false 调试模式
listen string ":8080" 监听地址
network string "tcp4" 网络协议
prefork bool false 是否启用 prefork
max_body_size string "1MB" 最大请求体大小
read_timeout string "5s" 读取超时
write_timeout string "10s" 写入超时

最佳实践

1. 项目组织
project/
├── cmd/
│   └── server/
│       └── main.go          # 应用入口
├── internal/
│   ├── handler/             # 处理器
│   │   ├── user.go
│   │   └── auth.go
│   ├── model/               # 数据模型
│   │   ├── user.go
│   │   └── order.go
│   ├── service/             # 业务逻辑
│   │   ├── user_service.go
│   │   └── auth_service.go
│   └── middleware/          # 中间件
│       ├── auth.go
│       └── logger.go
├── pkg/
│   └── utils/               # 工具函数
├── configs/
│   └── config.yaml          # 配置文件
├── migrations/              # 数据库迁移
├── scripts/                 # 部署脚本
├── tests/                   # 测试文件
├── go.mod
└── go.sum
2. 错误处理
// 定义业务错误
var (
    ErrUserNotFound = errors.New("用户不存在")
    ErrInvalidToken = errors.New("无效的令牌")
)

// 统一错误响应
func ErrorResponse(c core.Ctx, err error) {
    switch err {
    case ErrUserNotFound:
        c.SendStatus(404, err.Error())
    case ErrInvalidToken:
        c.SendStatus(401, err.Error())
    case gorm.ErrRecordNotFound:
        c.SendStatus(404, "记录不存在")
    default:
        core.Erro("未处理的错误: %v", err)
        c.SendStatus(500, "服务器内部错误")
    }
}

// 使用示例
func (Handler) GetUser(c core.Ctx) {
    user, err := services.GetUserByID(id)
    if err != nil {
        ErrorResponse(c, err)
        return
    }
    c.ToJSON(user)
}
3. 日志记录
// 配置日志
import "github.com/xs23933/core/v3/middleware/logger"

app.Use(logger.New(logger.Options{
    Format: "${time} ${status} ${method} ${path} ${latency}\n",
    Output: os.Stdout,
}))

// 自定义日志级别
core.Info("用户登录成功: %s", username)
core.Warn("API 调用频繁: %s", ip)
core.Erro("数据库连接失败: %v", err)
core.D("请求参数: %v", params)
日志轮转

框架内置日志文件轮转,配置文件方式:

log: /var/log/myapp/app.log
log_rotate:
  - size: 300M
  - daily
  - rotate: 30
  - compress
  - delaycompress: 24h
  - missingok
  - notifempty
  - copytruncate

只要配置了 loglog_rotate 未配置、为 null、空字符串或空数组,框架会自动套用上面的默认轮转配置。

参数说明:

参数 含义
size: 300M 日志文件达到指定大小后切割,支持 K/KB/M/MB/G/GB,也支持纯数字字节数
daily 按天切割,跨日期后第一次写入会创建新的日志文件
rotate: 30 保留最近 30 天的切割日志,超过期限自动删除
compress 切割后的日志文件压缩为 .gz
delaycompress 延迟压缩切割日志,默认延迟 24h,需配合 compress
delaycompress: 2h 指定延迟压缩时长,支持 Go duration 格式,如 30m2h24h
missingok 日志文件不存在时继续运行并重新创建,不返回错误
notifempty 当前日志文件为空时不切割、不压缩、不生成空的轮转文件
copytruncate 切割时复制当前日志再截断原文件,适合不希望替换文件句柄的部署方式

代码方式:

w, err := core.NewRotatingLogWriter(
    "/var/log/myapp/app.log",
    "size: 300M",
    "daily",
    "rotate: 30",
    "compress",
    "delaycompress: 24h",
    "missingok",
    "notifempty",
    "copytruncate",
)
if err != nil {
    panic(err)
}
defer w.Close()

app.Use(core.Logger(core.LoggerConfig{
    App:    app,
    Debug:  app.Debug,
    Output: w,
}))
4. 性能监控
import (
    "time"

    "github.com/xs23933/core/v3/middleware/metrics"
    "github.com/xs23933/core/v3/middleware/ratelimit"
)

// 启用指标收集
m, mw := metrics.New()
app.Use(mw)
metrics.Mount(app, "/metrics", m)

// 启用限流(默认内存)
app.Use(ratelimit.New(ratelimit.Config{
    Max:    300,
    Window: time.Minute,
}))

// 更平滑的用户级限流
app.Use(ratelimit.New(ratelimit.Config{
    Max:       120,
    Window:    time.Minute,
    Algorithm: ratelimit.SlidingWindow,
    KeyFunc: func(c core.Ctx) string {
        return c.GetString("user_id", c.RemoteIP().String())
    },
}))

扩展开发

1. 开发自定义中间件
package middleware

import (
    "time"

    "github.com/xs23933/core/v3"
)

func AccessLog() core.HandlerFunc {
    return func(c core.Ctx) error {
        start := time.Now()
        err := c.Next()
        core.Info("%s %s status=%d cost=%s",
            c.Method(), c.Path(), c.GetStatus(), time.Since(start))
        return err
    }
}
2. 开发插件
package plugin

import "github.com/xs23933/core/v3"

type Plugin struct {
    core.Handler
    config map[string]any
}

func New(config map[string]any) *Plugin {
    return &Plugin{
        config: config,
    }
}

func (p *Plugin) Install(app *core.Core) {
    // 注册路由
    app.Get("/plugin/status", p.Status)

    // 注册中间件
    app.Use(p.Middleware)

    // 初始化资源
    p.Init()
}

func (p *Plugin) Status(c core.Ctx) {
    c.ToJSON(map[string]any{
        "name":    p.config["name"],
        "version": p.config["version"],
        "status":  "running",
    })
}

func (p *Plugin) Middleware(c core.Ctx) error {
    // 插件中间件逻辑
    c.Set("plugin_data", p.config)
    return c.Next()
}

func (p *Plugin) Init() {
    // 初始化逻辑
    core.Info("插件 %s 已初始化", p.config["name"])
}

Core/V3 框架路由自动注册规范

本文档描述 github.com/xs23933/core/v3 框架的路由自动注册机制。


一、命名约定

1.1 Handler 结构体
type UserHandler struct {
    core.Handler  // 必须嵌入 core.Handler
    // ... 依赖字段
}
  • Handler 结构体名以 Handler 结尾
  • 框架自动注册时会去掉 Handler 后缀作为路由组名
  • 例:UserHandler → 路由组前缀为 /user(可通过 Init() 覆盖)
1.2 方法命名规则

HTTP 方法前缀 + 路径片段(驼峰命名):

方法名前缀 HTTP 方法
Get GET
Post POST
Put PUT
Delete DELETE
Patch PATCH
All ALL

二、路径转换规则(核心)

2.1 基本规则
字符特征 转换结果 示例
大写字母开头 路径片段 /xxx Profile/profile
下划线 + 小写字母 路径参数 :xxx _id:id
Param(固定关键字) 路径参数 :param Param:param
Params(固定关键字) 可选参数 :param? Params:param?
2.2 大写字母 = 路径分隔

每个大写字母开头的片段都会生成一个新的路径层级:

// 方法名 → 路由
func (h *Handler) GetProfile(c core.Ctx) error {}
// GET /profile

func (h *Handler) GetCurrentUser(c core.Ctx) error {}
// GET /current/user

func (h *Handler) GetId(c core.Ctx) error {}
// GET /id  (Id 是路径片段,不是参数!)
2.3 下划线 = 自定义路径参数

下划线开头 + 小写字母 = 自定义路径参数名:

// 方法名 → 路由
func (h *Handler) GetByID(c core.Ctx) error {}
// GET /:id

func (h *Handler) GetByUserid(c core.Ctx) error {}
// GET /:userid

func (h *Handler) GetByIDProfile(c core.Ctx) error {}
// GET /:id/profile
2.4 固定关键字 Param / Params

ParamParams 是框架固定关键字:

// 方法名 → 路由
func (h *Handler) GetParam(c core.Ctx) error {}
// GET /:param  (必选参数)

func (h *Handler) GetParams(c core.Ctx) error {}
// GET /:param?  (可选参数)

func (h *Handler) GetParam_Callback(c core.Ctx) error {}
// GET /:param/callback

func (h *Handler) GetParams_Detail(c core.Ctx) error {}
// GET /:param?/detail

⚠️ 关键区别:

  • Param:param(必选)
  • Params:param?(可选)
  • 参数名固定为 param,通过 c.Params("param") 获取

三、参数获取

3.1 固定关键字参数
// 路由: GET /:param
func (h *Handler) GetParam(c core.Ctx) error {
    val := c.Params("param")  // 参数名固定为 "param"
    // ...
}

// 路由: GET /:param/callback
func (h *Handler) GetParam_Callback(c core.Ctx) error {
    provider := c.Params("param")  // 同样是 "param"
    // ...
}
3.2 自定义参数名
// 路由: GET /:id
func (h *Handler) GetByID(c core.Ctx) error {
    id := c.Params("id")  // 参数名为 "id"
    // ...
}

// 路由: GET /:userid/profile
func (h *Handler) GetByUseridProfile(c core.Ctx) error {
    userId := c.Params("userId")  // 参数名为 "userId"
    // ...
}

四、路由前缀设置

4.1 默认前缀

框架根据 Handler 名称自动推断前缀:

type UserHandler struct { core.Handler }
// 默认前缀: /user

type OAuthHandler struct { core.Handler }
// 默认前缀: /oauth
4.2 自定义前缀

Init() 方法中使用 Prefix() 设置:

func (h *OAuthHandler) Init() {
    h.Prefix("/api/v1/oauth")
}

五、完整示例

5.1 OAuth Handler 示例
type OAuthHandler struct {
    core.Handler
    oauthService *OAuthService
}

func (h *OAuthHandler) Init() {
    h.Prefix("/api/v1/oauth")
}

// GET /api/v1/oauth/:param
func (h *OAuthHandler) GetParam(c core.Ctx) error {
    provider := c.Params("param") // google, facebook, twitter, github
    // ...
}

// GET /api/v1/oauth/:param/callback
func (h *OAuthHandler) GetParam_Callback(c core.Ctx) error {
    provider := c.Params("param")
    // ...
}

生成的路由

GET /api/v1/oauth/:param           → OAuthHandler.GetParam
GET /api/v1/oauth/:param/callback  → OAuthHandler.GetParam_Callback

访问示例

URL 匹配路由 param 值
GET /api/v1/oauth/google GetParam "google"
GET /api/v1/oauth/facebook/callback GetParam_Callback "facebook"
GET /api/v1/oauth 404 必选参数缺失
5.2 User Handler 示例
type UserHandler struct {
    core.Handler
}

func (h *UserHandler) Init() {
    h.Prefix("/api/v1/users")
}

// GET /api/v1/users
func (h *UserHandler) Get(c core.Ctx) error {}

// GET /api/v1/users/:id
func (h *UserHandler) GetByID(c core.Ctx) error {
    id := c.Params("id")
}

// GET /api/v1/users/:id/profile
func (h *UserHandler) GetByID_Profile(c core.Ctx) error {
    id := c.Params("id")
}

// GET /api/v1/users/current
func (h *UserHandler) GetCurrent(c core.Ctx) error {}

// POST /api/v1/users
func (h *UserHandler) Post(c core.Ctx) error {}

// PUT /api/v1/users/:id
func (h *UserHandler) Put_id(c core.Ctx) error {}

// DELETE /api/v1/users/:id
func (h *UserHandler) Delete_id(c core.Ctx) error {}

六、命名转换规则(ToNamer)

框架内部使用 ToNamer 函数进行命名转换:

转换逻辑

  1. 提取 HTTP 方法前缀(Get/Post/Put/Delete/Patch
  2. 遍历剩余字符:
    • 大写字母 → 新路径片段(转小写)
    • _ + 小写字母 → 自定义路径参数
    • Param(关键字)→ :param
    • Params(关键字)→ :param?

转换示例

方法名 解析过程 最终路由
GetProfile Profile/profile GET /profile
GetCurrentUser Current + User/current/user GET /current/user
GetByID ByID/:id GET /:id
Get_userId _userId/:userId GET /:userId
GetByID_Profile _id + Profile/:id/profile GET /:id/profile
GetParam Param/:param GET /:param
GetParam_Callback Param + Callback/:param/callback GET /:param/callback
GetParams Params/:param? GET /:param?
GetParams_Detail Params + Detail/:param?/detail GET /:param?/detail
GetId Id/id GET /id(不是参数!)
PostLogin Login/login POST /login

七、常见错误

7.1 混淆大写和下划线
// ❌ 错误:期望 /:id,实际得到 /id
func (h *Handler) GetId(c core.Ctx) error {}
// GET /id  (Id 是路径片段,不是参数)

// ✅ 正确:使用下划线定义参数
func (h *Handler) GetByID(c core.Ctx) error {}
// GET /:id
7.2 混淆 Param 和 Params
// ❌ 错误:期望可选参数,实际是必选
func (h *Handler) GetParam(c core.Ctx) error {}
// GET /:param  (必选)

// ✅ 正确:使用 Params 表示可选
func (h *Handler) GetParams(c core.Ctx) error {}
// GET /:param?  (可选)
7.3 Param 与自定义参数混用
// ⚠️ 注意:Param 固定参数名为 "param"
func (h *Handler) GetParam(c core.Ctx) error {}
// GET /:param,用 c.Params("param") 获取

// 自定义参数名用下划线
func (h *Handler) GetByID(c core.Ctx) error {}
// GET /:id,用 c.Params("id") 获取

八、调试技巧

8.1 查看注册的路由

框架启动时会打印所有注册的路由:

[DBUG] AutoRoute handler.UserHandler
[DBUG] route: GET /profile > handler.UserHandler.GetProfile
[DBUG] route: POST /login > handler.AuthHandler.PostLogin
[DBUG] route: GET /api/v1/oauth/:param > handler.OAuthHandler.GetParam
8.2 常见问题排查
问题 原因 解决方案
404 路由不匹配 参数必选但未提供 使用 Params 改为可选,或确保 URL 包含参数
参数值为空 使用 Params 但未传参 检查是否应该用 Param 改为必选
路由不是参数 用了大写开头(如 Id 改用下划线开头(如 _id
路由冲突 多个方法映射到同一路径 检查方法命名是否重复

九、快速参考卡

┌─────────────────────────────────────────────────────────────┐
│  命名规则                                                    │
├─────────────────────────────────────────────────────────────┤
│  大写字母开头    → 路径片段 /xxx                              │
│  _xxx(下划线)  → 自定义路径参数 :xxx                        │
│  Param(关键字) → 路径参数 :param(必选)                    │
│  Params(关键字)→ 路径参数 :param?(可选)                   │
├─────────────────────────────────────────────────────────────┤
│  方法名               →  路由                               │
├─────────────────────────────────────────────────────────────┤
│  Get                  →  GET /                              │
│  GetProfile           →  GET /profile                       │
│  GetCurrent           →  GET /current                       │
│  GetCurrentProfile    →  GET /current/profile               │
│  GetByID              →  GET /:id       (自定义参数)          │
│  GetUserid            →  GET /:userid   (自定义参数)         │
│  GetByID_Profile      →  GET /:id/profile                   │
│  GetParam             →  GET /:param     (必选关键字)        │
│  GetParam_Callback    →  GET /:param/callback               │
│  GetParams            →  GET /:param?    (可选关键字)        │
│  GetParams_Detail     →  GET /:param?/detail                │
│  GetId                →  GET /id       (不是参数!)          │
│  Post                 →  POST /                             │
│  PostLogin            →  POST /login                        │
│  PutID                →  PUT /:id                           │
│  DeleteID             →  DELETE /:id                        │
└─────────────────────────────────────────────────────────────┘

参数获取:
  - 关键字参数: c.Params("param")
  - 自定义参数: c.Params("id"), c.Params("userId") 等

版本历史

v3.1.0 (当前版本)
  • 支持 Go 1.24
  • 性能优化,提升 30% 吞吐量
  • 新增 WebSocket 支持
  • 改进中间件系统
  • 增强数据库支持
v2.0
  • 引入自动路由注册
  • 支持多数据库连接
  • 改进错误处理机制
  • 新增文件上传功能
v1.0
  • 初始版本发布
  • 基础路由功能
  • 数据库集成
  • 中间件支持

社区支持

贡献指南

欢迎贡献代码!请遵循以下步骤:

  1. Fork 项目仓库
  2. 创建功能分支 (git checkout -b feature/amazing-feature)
  3. 提交更改 (git commit -m 'Add some amazing feature')
  4. 推送到分支 (git push origin feature/amazing-feature)
  5. 创建 Pull Request

许可证

本项目采用 MIT 许可证。详见 LICENSE 文件。


文档最后更新: 2026-03-31 Core Framework v3.0.0

Documentation

Overview

grpc.go

Index

Constants

View Source
const (
	MIMETextXML         = "text/xml"
	MIMETextHTML        = "text/html"
	MIMETextPlain       = "text/plain"
	MIMETextJavaScript  = "text/javascript"
	MIMEApplicationXML  = "application/xml"
	MIMEApplicationJSON = "application/json"
	// Deprecated: use MIMETextJavaScript instead
	MIMEApplicationJavaScript = "application/javascript"
	MIMEApplicationForm       = "application/x-www-form-urlencoded"
	MIMEOctetStream           = "application/octet-stream"
	MIMEMultipartForm         = "multipart/form-data"

	MIMETextXMLCharsetUTF8         = "text/xml; charset=utf-8"
	MIMETextHTMLCharsetUTF8        = "text/html; charset=utf-8"
	MIMETextPlainCharsetUTF8       = "text/plain; charset=utf-8"
	MIMETextJavaScriptCharsetUTF8  = "text/javascript; charset=utf-8"
	MIMEApplicationXMLCharsetUTF8  = "application/xml; charset=utf-8"
	MIMEApplicationJSONCharsetUTF8 = "application/json; charset=utf-8"
	// Deprecated: use MIMETextJavaScriptCharsetUTF8 instead
	MIMEApplicationJavaScriptCharsetUTF8 = "application/javascript; charset=utf-8"
)

MIME types that are commonly used

View Source
const (
	CharsetUTF8    = "utf-8"
	CharsetGBK     = "gbk"
	CharsetGB2312  = "gb2312"
	CharsetGB18030 = "gb18030"
)
View Source
const (
	StatusContinue           = 100 // RFC 9110, 15.2.1
	StatusSwitchingProtocols = 101 // RFC 9110, 15.2.2
	StatusProcessing         = 102 // RFC 2518, 10.1
	StatusEarlyHints         = 103 // RFC 8297

	StatusOK                          = 200 // RFC 9110, 15.3.1
	StatusCreated                     = 201 // RFC 9110, 15.3.2
	StatusAccepted                    = 202 // RFC 9110, 15.3.3
	StatusNonAuthoritativeInformation = 203 // RFC 9110, 15.3.4
	StatusNoContent                   = 204 // RFC 9110, 15.3.5
	StatusResetContent                = 205 // RFC 9110, 15.3.6
	StatusPartialContent              = 206 // RFC 9110, 15.3.7
	StatusMultiStatus                 = 207 // RFC 4918, 11.1
	StatusAlreadyReported             = 208 // RFC 5842, 7.1
	StatusIMUsed                      = 226 // RFC 3229, 10.4.1

	StatusMultipleChoices   = 300 // RFC 9110, 15.4.1
	StatusMovedPermanently  = 301 // RFC 9110, 15.4.2
	StatusFound             = 302 // RFC 9110, 15.4.3
	StatusSeeOther          = 303 // RFC 9110, 15.4.4
	StatusNotModified       = 304 // RFC 9110, 15.4.5
	StatusUseProxy          = 305 // RFC 9110, 15.4.6
	StatusSwitchProxy       = 306 // RFC 9110, 15.4.7 (Unused)
	StatusTemporaryRedirect = 307 // RFC 9110, 15.4.8
	StatusPermanentRedirect = 308 // RFC 9110, 15.4.9

	StatusBadRequest                   = 400 // RFC 9110, 15.5.1
	StatusUnauthorized                 = 401 // RFC 9110, 15.5.2
	StatusPaymentRequired              = 402 // RFC 9110, 15.5.3
	StatusForbidden                    = 403 // RFC 9110, 15.5.4
	StatusNotFound                     = 404 // RFC 9110, 15.5.5
	StatusMethodNotAllowed             = 405 // RFC 9110, 15.5.6
	StatusNotAcceptable                = 406 // RFC 9110, 15.5.7
	StatusProxyAuthRequired            = 407 // RFC 9110, 15.5.8
	StatusRequestTimeout               = 408 // RFC 9110, 15.5.9
	StatusConflict                     = 409 // RFC 9110, 15.5.10
	StatusGone                         = 410 // RFC 9110, 15.5.11
	StatusLengthRequired               = 411 // RFC 9110, 15.5.12
	StatusPreconditionFailed           = 412 // RFC 9110, 15.5.13
	StatusRequestEntityTooLarge        = 413 // RFC 9110, 15.5.14
	StatusRequestURITooLong            = 414 // RFC 9110, 15.5.15
	StatusUnsupportedMediaType         = 415 // RFC 9110, 15.5.16
	StatusRequestedRangeNotSatisfiable = 416 // RFC 9110, 15.5.17
	StatusExpectationFailed            = 417 // RFC 9110, 15.5.18
	StatusTeapot                       = 418 // RFC 9110, 15.5.19 (Unused)
	StatusMisdirectedRequest           = 421 // RFC 9110, 15.5.20
	StatusUnprocessableEntity          = 422 // RFC 9110, 15.5.21
	StatusLocked                       = 423 // RFC 4918, 11.3
	StatusFailedDependency             = 424 // RFC 4918, 11.4
	StatusTooEarly                     = 425 // RFC 8470, 5.2.
	StatusUpgradeRequired              = 426 // RFC 9110, 15.5.22
	StatusPreconditionRequired         = 428 // RFC 6585, 3
	StatusTooManyRequests              = 429 // RFC 6585, 4
	StatusRequestHeaderFieldsTooLarge  = 431 // RFC 6585, 5
	StatusUnavailableForLegalReasons   = 451 // RFC 7725, 3

	StatusInternalServerError           = 500 // RFC 9110, 15.6.1
	StatusNotImplemented                = 501 // RFC 9110, 15.6.2
	StatusBadGateway                    = 502 // RFC 9110, 15.6.3
	StatusServiceUnavailable            = 503 // RFC 9110, 15.6.4
	StatusGatewayTimeout                = 504 // RFC 9110, 15.6.5
	StatusHTTPVersionNotSupported       = 505 // RFC 9110, 15.6.6
	StatusVariantAlsoNegotiates         = 506 // RFC 2295, 8.1
	StatusInsufficientStorage           = 507 // RFC 4918, 11.5
	StatusLoopDetected                  = 508 // RFC 5842, 7.2
	StatusNotExtended                   = 510 // RFC 2774, 7
	StatusNetworkAuthenticationRequired = 511 // RFC 6585, 6
)

HTTP status codes were copied from https://github.com/nginx/nginx/blob/67d2a9541826ecd5db97d604f23460210fd3e517/conf/mime.types with the following updates: - Rename StatusNonAuthoritativeInfo to StatusNonAuthoritativeInformation - Add StatusSwitchProxy (306) NOTE: Keep this list in sync with statusMessage

View Source
const (
	HeaderAuthorization                   = "Authorization"
	HeaderProxyAuthenticate               = "Proxy-Authenticate"
	HeaderProxyAuthorization              = "Proxy-Authorization"
	HeaderWWWAuthenticate                 = "WWW-Authenticate"
	HeaderAge                             = "Age"
	HeaderCacheControl                    = "Cache-Control"
	HeaderClearSiteData                   = "Clear-Site-Data"
	HeaderExpires                         = "Expires"
	HeaderPragma                          = "Pragma"
	HeaderWarning                         = "Warning"
	HeaderAcceptCH                        = "Accept-CH"
	HeaderAcceptCHLifetime                = "Accept-CH-Lifetime"
	HeaderContentDPR                      = "Content-DPR"
	HeaderDPR                             = "DPR"
	HeaderEarlyData                       = "Early-Data"
	HeaderSaveData                        = "Save-Data"
	HeaderViewportWidth                   = "Viewport-Width"
	HeaderWidth                           = "Width"
	HeaderETag                            = "ETag"
	HeaderIfMatch                         = "If-Match"
	HeaderIfModifiedSince                 = "If-Modified-Since"
	HeaderIfNoneMatch                     = "If-None-Match"
	HeaderIfUnmodifiedSince               = "If-Unmodified-Since"
	HeaderLastModified                    = "Last-Modified"
	HeaderVary                            = "Vary"
	HeaderConnection                      = "Connection"
	HeaderKeepAlive                       = "Keep-Alive"
	HeaderAccept                          = "Accept"
	HeaderAcceptCharset                   = "Accept-Charset"
	HeaderAcceptEncoding                  = "Accept-Encoding"
	HeaderAcceptLanguage                  = "Accept-Language"
	HeaderCookie                          = "Cookie"
	HeaderExpect                          = "Expect"
	HeaderMaxForwards                     = "Max-Forwards"
	HeaderSetCookie                       = "Set-Cookie"
	HeaderAccessControlAllowCredentials   = "Access-Control-Allow-Credentials"
	HeaderAccessControlAllowHeaders       = "Access-Control-Allow-Headers"
	HeaderAccessControlAllowMethods       = "Access-Control-Allow-Methods"
	HeaderAccessControlAllowOrigin        = "Access-Control-Allow-Origin"
	HeaderAccessControlExposeHeaders      = "Access-Control-Expose-Headers"
	HeaderAccessControlMaxAge             = "Access-Control-Max-Age"
	HeaderAccessControlRequestHeaders     = "Access-Control-Request-Headers"
	HeaderAccessControlRequestMethod      = "Access-Control-Request-Method"
	HeaderOrigin                          = "Origin"
	HeaderTimingAllowOrigin               = "Timing-Allow-Origin"
	HeaderXPermittedCrossDomainPolicies   = "X-Permitted-Cross-Domain-Policies"
	HeaderDNT                             = "DNT"
	HeaderTk                              = "Tk"
	HeaderContentDisposition              = "Content-Disposition"
	HeaderContentEncoding                 = "Content-Encoding"
	HeaderContentLanguage                 = "Content-Language"
	HeaderContentLength                   = "Content-Length"
	HeaderContentLocation                 = "Content-Location"
	HeaderContentType                     = "Content-Type"
	HeaderForwarded                       = "Forwarded"
	HeaderVia                             = "Via"
	HeaderXForwardedFor                   = "X-Forwarded-For"
	HeaderXForwardedHost                  = "X-Forwarded-Host"
	HeaderXForwardedProto                 = "X-Forwarded-Proto"
	HeaderXForwardedProtocol              = "X-Forwarded-Protocol"
	HeaderXForwardedSsl                   = "X-Forwarded-Ssl"
	HeaderXUrlScheme                      = "X-Url-Scheme"
	HeaderLocation                        = "Location"
	HeaderFrom                            = "From"
	HeaderHost                            = "Host"
	HeaderReferer                         = "Referer"
	HeaderReferrerPolicy                  = "Referrer-Policy"
	HeaderUserAgent                       = "User-Agent"
	HeaderAllow                           = "Allow"
	HeaderServer                          = "Server"
	HeaderAcceptRanges                    = "Accept-Ranges"
	HeaderContentRange                    = "Content-Range"
	HeaderIfRange                         = "If-Range"
	HeaderRange                           = "Range"
	HeaderContentSecurityPolicy           = "Content-Security-Policy"
	HeaderContentSecurityPolicyReportOnly = "Content-Security-Policy-Report-Only"
	HeaderCrossOriginResourcePolicy       = "Cross-Origin-Resource-Policy"
	HeaderExpectCT                        = "Expect-CT"
	HeaderPermissionsPolicy               = "Permissions-Policy"
	HeaderPublicKeyPins                   = "Public-Key-Pins"
	HeaderPublicKeyPinsReportOnly         = "Public-Key-Pins-Report-Only"
	HeaderStrictTransportSecurity         = "Strict-Transport-Security"
	HeaderUpgradeInsecureRequests         = "Upgrade-Insecure-Requests"
	HeaderXContentTypeOptions             = "X-Content-Type-Options"
	HeaderXDownloadOptions                = "X-Download-Options"
	HeaderXFrameOptions                   = "X-Frame-Options"
	HeaderXPoweredBy                      = "X-Powered-By"
	HeaderXXSSProtection                  = "X-XSS-Protection"
	HeaderLastEventID                     = "Last-Event-ID"
	HeaderNEL                             = "NEL"
	HeaderPingFrom                        = "Ping-From"
	HeaderPingTo                          = "Ping-To"
	HeaderReportTo                        = "Report-To"
	HeaderTE                              = "TE"
	HeaderTrailer                         = "Trailer"
	HeaderTransferEncoding                = "Transfer-Encoding"
	HeaderSecWebSocketAccept              = "Sec-WebSocket-Accept"
	HeaderSecWebSocketExtensions          = "Sec-WebSocket-Extensions"
	HeaderSecWebSocketKey                 = "Sec-WebSocket-Key"
	HeaderSecWebSocketProtocol            = "Sec-WebSocket-Protocol"
	HeaderSecWebSocketVersion             = "Sec-WebSocket-Version"
	HeaderAcceptPatch                     = "Accept-Patch"
	HeaderAcceptPushPolicy                = "Accept-Push-Policy"
	HeaderAcceptSignature                 = "Accept-Signature"
	HeaderAltSvc                          = "Alt-Svc"
	HeaderDate                            = "Date"
	HeaderIndex                           = "Index"
	HeaderLargeAllocation                 = "Large-Allocation"
	HeaderLink                            = "Link"
	HeaderPushPolicy                      = "Push-Policy"
	HeaderRetryAfter                      = "Retry-After"
	HeaderServerTiming                    = "Server-Timing"
	HeaderSignature                       = "Signature"
	HeaderSignedHeaders                   = "Signed-Headers"
	HeaderSourceMap                       = "SourceMap"
	HeaderUpgrade                         = "Upgrade"
	HeaderXDNSPrefetchControl             = "X-DNS-Prefetch-Control"
	HeaderXPingback                       = "X-Pingback"
	HeaderXRequestID                      = "X-Request-ID"
	HeaderXRequestedWith                  = "X-Requested-With"
	HeaderXRobotsTag                      = "X-Robots-Tag"
	HeaderXUACompatible                   = "X-UA-Compatible"
)

HTTP Headers were copied from net/http.

View Source
const (
	DefaultDateFormat     = "2006-01-02"
	DefaultDateTimeFormat = "2006-01-02 15:04"
)
View Source
const (
	ConstraintInt             = "int"
	ConstraintBool            = "bool"
	ConstraintFloat           = "float"
	ConstraintAlpha           = "alpha"
	ConstraintGUID            = "guid"
	ConstraintMinLen          = "minLen"
	ConstraintMaxLen          = "maxLen"
	ConstraintLen             = "len"
	ConstraintBetweenLen      = "betweenLen"
	ConstraintMinLenLower     = "minlen"
	ConstraintMaxLenLower     = "maxlen"
	ConstraintBetweenLenLower = "betweenlen"
	ConstraintMin             = "min"
	ConstraintMax             = "max"
	ConstraintRange           = "range"
	ConstraintDatetime        = "datetime"
	ConstraintRegex           = "regex"
)

Route Constraints

View Source
const CoreHeader = `` /* 185-byte string literal not displayed */
View Source
const VERSION = "v3"

Variables

View Source
var (
	MethodUse     = Methods[METHOD_USE]
	MethodGet     = Methods[METHOD_GET]
	MethodPost    = Methods[METHOD_POST]
	MethodHead    = Methods[METHOD_HEAD]
	MethodPut     = Methods[METHOD_PUT]
	MethodDelete  = Methods[METHOD_DELETE]
	MethodOptions = Methods[METHOD_OPTIONS]
	MethodConnect = Methods[METHOD_CONNECT]
	MethodTrace   = Methods[METHOD_TRACE]
	MethodPatch   = Methods[METHOD_PATCH]
	MethodAll     = Methods[METHOD_ALL]
)
View Source
var (
	ErrDataTypeNotSupport       = errors.New("dataType does not support")
	ErrNoConfig                 = errors.New("field global configuration not found")
	ErrLayoutCalledUnexpectedly = errors.New("layout called unexpectedly")
)
View Source
var (
	ErrBadRequest                   = NewError(StatusBadRequest)                   // 400
	ErrUnauthorized                 = NewError(StatusUnauthorized)                 // 401
	ErrPaymentRequired              = NewError(StatusPaymentRequired)              // 402
	ErrForbidden                    = NewError(StatusForbidden)                    // 403
	ErrNotFound                     = NewError(StatusNotFound)                     // 404
	ErrMethodNotAllowed             = NewError(StatusMethodNotAllowed)             // 405
	ErrNotAcceptable                = NewError(StatusNotAcceptable)                // 406
	ErrProxyAuthRequired            = NewError(StatusProxyAuthRequired)            // 407
	ErrRequestTimeout               = NewError(StatusRequestTimeout)               // 408
	ErrConflict                     = NewError(StatusConflict)                     // 409
	ErrGone                         = NewError(StatusGone)                         // 410
	ErrLengthRequired               = NewError(StatusLengthRequired)               // 411
	ErrPreconditionFailed           = NewError(StatusPreconditionFailed)           // 412
	ErrRequestEntityTooLarge        = NewError(StatusRequestEntityTooLarge)        // 413
	ErrRequestURITooLong            = NewError(StatusRequestURITooLong)            // 414
	ErrUnsupportedMediaType         = NewError(StatusUnsupportedMediaType)         // 415
	ErrRequestedRangeNotSatisfiable = NewError(StatusRequestedRangeNotSatisfiable) // 416
	ErrExpectationFailed            = NewError(StatusExpectationFailed)            // 417
	ErrTeapot                       = NewError(StatusTeapot)                       // 418
	ErrMisdirectedRequest           = NewError(StatusMisdirectedRequest)           // 421
	ErrUnprocessableEntity          = NewError(StatusUnprocessableEntity)          // 422
	ErrLocked                       = NewError(StatusLocked)                       // 423
	ErrFailedDependency             = NewError(StatusFailedDependency)             // 424
	ErrTooEarly                     = NewError(StatusTooEarly)                     // 425
	ErrUpgradeRequired              = NewError(StatusUpgradeRequired)              // 426
	ErrPreconditionRequired         = NewError(StatusPreconditionRequired)         // 428
	ErrTooManyRequests              = NewError(StatusTooManyRequests)              // 429
	ErrRequestHeaderFieldsTooLarge  = NewError(StatusRequestHeaderFieldsTooLarge)  // 431
	ErrUnavailableForLegalReasons   = NewError(StatusUnavailableForLegalReasons)   // 451

	ErrInternalServerError           = NewError(StatusInternalServerError)           // 500
	ErrNotImplemented                = NewError(StatusNotImplemented)                // 501
	ErrBadGateway                    = NewError(StatusBadGateway)                    // 502
	ErrServiceUnavailable            = NewError(StatusServiceUnavailable)            // 503
	ErrGatewayTimeout                = NewError(StatusGatewayTimeout)                // 504
	ErrHTTPVersionNotSupported       = NewError(StatusHTTPVersionNotSupported)       // 505
	ErrVariantAlsoNegotiates         = NewError(StatusVariantAlsoNegotiates)         // 506
	ErrInsufficientStorage           = NewError(StatusInsufficientStorage)           // 507
	ErrLoopDetected                  = NewError(StatusLoopDetected)                  // 508
	ErrNotExtended                   = NewError(StatusNotExtended)                   // 510
	ErrNetworkAuthenticationRequired = NewError(StatusNetworkAuthenticationRequired) // 511
)

Errors

View Source
var (
	DefaultErrorWriter io.Writer = os.Stderr
	LogHub                       = NewLogMonitor()
)

DefaultErrorWriter is the default io.Writer used by Gin to debug errors

View Source
var (
	SnID *sid.SnowflakeID
	XID  *xid.Generator
)
View Source
var (
	// AESKey AES-256 密钥(32字节)
	AESKey = []byte("this-is-a-32-byte-key-for-aes256")
)
View Source
var DefaultLogRotateOptions = []string{
	"size: 300M",
	"daily",
	"rotate: 30",
	"compress",
	"delaycompress: 24h",
	"missingok",
	"notifempty",
	"copytruncate",
}
View Source
var (
	DefaultOutput = io.Discard
)
View Source
var (
	ErrInvalidValidationType = NewError(400, "验证类型必须是结构体指针")
)

全局验证器实例 自定义错误类型

View Source
var (
	Methods = []string{
		"GET",
		"POST",
		"HEAD",
		"PUT",
		"DELETE",
		"OPTIONS",
		"CONNECT",
		"TRACE",
		"PATCH",
		"ALL",
		"USE",
	}
)
View Source
var UuidNil = UUID{uuid.Nil}

Functions

func CheckPassword added in v3.1.16

func CheckPassword(password, hash string) bool

CheckPassword 验证密码

func CloseNSQ added in v3.1.17

func CloseNSQ()

CloseNSQ 关闭所有 NSQ 连接

func CloseRedis added in v3.1.17

func CloseRedis()

CloseRedis 关闭所有 Redis 连接

func Contains

func Contains[S ~[]E, E comparable](s S, v E) bool

func ContainsAny

func ContainsAny(elems Array, v any) bool

func D

func D(f string, args ...any)

func DBType

func DBType(name ...string) string

func DecryptAES added in v3.1.16

func DecryptAES(ciphertext string) (string, error)

DecryptAES AES-256-GCM 解密

func DecryptAESBytes added in v3.1.16

func DecryptAESBytes(ciphertext []byte) ([]byte, error)

DecryptAESBytes AES-256-GCM 解密

func DefaultErrorHandler

func DefaultErrorHandler(c Ctx, err error) error

func Delete

func Delete[S ~[]E, E any](s S, i, j int) S

Delete removes the elements s[i:j] from s, returning the modified slice. Delete panics if s[i:j] is not a valid slice of s. Delete is O(len(s)-j), so if many items must be deleted, it is better to make a single call deleting them all together than to delete one at a time. Delete might not modify the elements s[len(s)-(j-i):len(s)]. If those elements contain pointers you might consider zeroing those elements so that objects they reference can be garbage collected.

func Dir

func Dir(root string, listDirectory bool) http.FileSystem

Dir returns a http.FileSystem that can be used by http.FileServer(). It is used internally in router.Static(). if listDirectory == true, then it works the same as http.Dir() otherwise it returns a filesystem that prevents http.FileServer() to list the directory files.

func Dump

func Dump(v ...any)

Dump 打印数据信息

func EncryptAES added in v3.1.16

func EncryptAES(plaintext string) (string, error)

EncryptAES AES-256-GCM 加密

func EncryptAESBytes added in v3.1.16

func EncryptAESBytes(plaintext []byte) ([]byte, error)

EncryptAESBytes AES-256-GCM 加密

func EnumFromString

func EnumFromString[T Enum](str string, mapping []string) T

EnumFromString 字符串转枚举值

func TypeXFromString(str string) TypeX {
	return EnumFromString[TypeX](str, TypeXMap)
}

func EnumMarshalJSON

func EnumMarshalJSON[T Enum](val T, mapping []string) ([]byte, error)

EnumMarshalJSON 枚举 JSON 序列化

func EnumMarshalText added in v3.1.6

func EnumMarshalText[T Enum](v T, mapping []string) ([]byte, error)

func EnumString

func EnumString[T Enum](val T, mapping []string) string

EnumString 枚举值转字符串

func (s TypeX) String() string {
	return EnumString(s, TypeXMap)
}

func EnumUnmarshalJSON

func EnumUnmarshalJSON[T Enum](data []byte, mapping []string) (T, error)

EnumUnmarshalJSON 枚举 JSON 反序列化

func EnumUnmarshalText added in v3.1.6

func EnumUnmarshalText[T Enum](data []byte, mapping []string) (T, error)

func EqualFold

func EqualFold[S byteSeq](b, s S) bool

EqualFold tests ascii strings or bytes for equality case-insensitively

func Erro

func Erro(f string, args ...any)

error logger

func Exists

func Exists(absDir string) bool

Exists check file or path exists

func Expr

func Expr(expr string, args ...any) clause.Expr

func ExtractPrimaryDomain added in v3.1.10

func ExtractPrimaryDomain(host string) string

ExtractPrimaryDomain 提取一级域名(主域名) 示例:

"webin.work" -> "webin.work"
"www.webin.work" -> "webin.work"
"api.webin.work" -> "webin.work"
"customer.com" -> "customer.com"
"www.customer.com" -> "customer.com"

func Filter added in v3.0.7

func Filter[T any](slice []T, test func(T) bool) []T

Filter 过滤

activeUsers := core.Filter(users, func(u User) bool {
    return u.Status == "active"
})

func Find

func Find(out any, args ...any) error

Find find all data record max 10000

func FixURI

func FixURI(pre, src, tag string) string

func GetTrimmedParam

func GetTrimmedParam(param string) string

GetTrimmedParam trims the ':' & '?' from a string

func GrpcHeader added in v3.1.16

func GrpcHeader(ctx context.Context, key string) string

func HashPassword added in v3.1.16

func HashPassword(password string) (string, error)

HashPassword 使用 bcrypt 哈希密码(使用默认 cost)

func HashPasswordWithCost added in v3.1.16

func HashPasswordWithCost(password string, cost int) (string, error)

HashPasswordWithCost 使用 bcrypt 哈希密码,可指定 cost

func Index

func Index[S ~[]E, E comparable](s S, v E) int

func Info

func Info(f string, args ...any)

info logger

func InitNSQ added in v3.1.17

func InitNSQ(conf Options, debug bool) error

InitNSQ 初始化 NSQ(从配置自动创建 Producer)

func IsChild

func IsChild() bool

IsChild determines if the current process is a child of Prefork

func IsErrors

func IsErrors(v any) bool

func IsInvalidLengthError

func IsInvalidLengthError(err error) bool

IsInvalidLengthError is matcher function for custom error invalidLengthError

func IsNumeric added in v3.0.7

func IsNumeric(s string) bool

func LocalIP

func LocalIP() (ip net.IP, err error)

func Log

func Log(f string, args ...any)

func LogRotateOptionsFromConfig added in v3.1.19

func LogRotateOptionsFromConfig(conf Options) []string

func MIME

func MIME(extension string) (mime string)

GetMIME returns the content-type of a file extension

func MakePath

func MakePath(name, dst string, args ...any) (string, string, error)

MakePath make dir

path = {root}/{dst}/{id}
@param
name string filename
dst string dst path
root string root path optional
id   path optional type uid.UID, int, uint, int64,uint64
rename bool optional
return relPath, absPath

 `
   MakePath("favicon.png", "/images")
   (string) relpath "/images/10/favicon.png"
   (string) abspath "/images/10/favicon.png"

   MakePath("favicon.png", "/images", "/static")
   (string) relpath "/images/10/5hsbkthaadld/favicon.png"
   (string) abspath "/static/images/10/5hsbkthaadld/favicon.png"

   MakePath("favicon.png", "/images", "/static", uid.New())
   (string) relpath "/images/10/5hsbkthaadld/5hsbkthaadld.png"
   (string) abspath "/static/images/10/5hsbkthaadld/5hsbkthaadld.png"
              👇filename    👇dst      👇root     👇id      👇rename
   MakePath("favicon.png", "/images", "/static", uid.New(), true)
   (string) relpath "/images/10/5hsbkthaadld/5hsbkthaadld.png"
   (string) abspath "/static/images/10/5hsbkthaadld/5hsbkthaadld.png"
 `

func NSQDecodeJSON added in v3.1.17

func NSQDecodeJSON(msg *nsq.Message, v any) error

NSQDecodeJSON 从 nsq.Message.Body 解析 JSON

func NSQDecodeStdJSON added in v3.1.17

func NSQDecodeStdJSON(msg *nsq.Message, v any) error

NSQDecodeStdJSON 从 nsq.Message.Body 解析 JSON(标准库)

func NSQDeferredPublish added in v3.1.17

func NSQDeferredPublish(topic string, delay time.Duration, body []byte) error

NSQDeferredPublish 快速延迟发布

func NSQDeferredPublishJSON added in v3.1.17

func NSQDeferredPublishJSON(topic string, delay time.Duration, v any) error

NSQDeferredPublishJSON 快速延迟发布 JSON

func NSQHandlerWithTimeout added in v3.1.17

func NSQHandlerWithTimeout(timeout time.Duration, handler func(ctx context.Context, msg *nsq.Message) error) nsq.HandlerFunc

NSQHandlerWithTimeout 包装 handler,为每条消息创建带超时的 context

func NSQParse added in v3.1.17

func NSQParse[T any](msg *nsq.Message) (*T, error)

NSQMessage 泛型消息解析辅助 用法:msg, _ := core.NSQParse[Order](nsqMsg)

func NSQPublish added in v3.1.17

func NSQPublish(topic string, body []byte) error

NSQPublish 快速发布消息到指定 topic

func NSQPublishJSON added in v3.1.17

func NSQPublishJSON(topic string, v any) error

NSQPublishJSON 快速发布 JSON 消息

func NSQPublishString added in v3.1.17

func NSQPublishString(topic, message string) error

NSQPublishString 快速发布字符串消息

func NewModel

func NewModel(conf Options, debug, colorful bool) (map[string]*DB, error)

func NewNID added in v3.1.19

func NewNID() nid.ID

func NewRedis added in v3.1.17

func NewRedis(conf Options, debug bool) (map[string]*RedisClient, error)

NewRedis 根据配置初始化 Redis 连接 支持单实例和多实例两种配置格式

func NewSnID added in v3.0.3

func NewSnID() sid.ID

func NewXID added in v3.1.3

func NewXID() xid.ID

func NormalizeHeaders added in v3.1.7

func NormalizeHeaders(h http.Header)

func PrintJSON

func PrintJSON(v any, tags ...any)

func RegHandle

func RegHandle(mods ...any)

func RegisterModule

func RegisterModule(inst module)

func RemoteIP added in v3.1.10

func RemoteIP(h iGet, ip string) net.IP

func Remove

func Remove[T comparable](elems []T, v T) []T

删除指定元素

func RemoveAll added in v3.1.10

func RemoveAll[S ~[]E, E comparable](s S, v E) S

RemoveAll 删除所有匹配的元素

func RemoveDuplicates

func RemoveDuplicates[T comparable](slice []T) []T

RemoveDuplicates 去重函数,适用于任何类型的切片

func RemoveEscapeChar

func RemoveEscapeChar(word string) string

RemoveEscapeChar removes escape characters

func RemoveEscapeCharBytes

func RemoveEscapeCharBytes(word []byte) []byte

RemoveEscapeCharBytes removes escape characters

func RoutePatternMatch

func RoutePatternMatch(path, pattern string, cfg ...Options) bool

RoutePatternMatch checks if a given path matches a core route pattern.

func SHA256 added in v3.1.15

func SHA256(s string) string

func SHA256Hash added in v3.1.16

func SHA256Hash(data string) string

SHA256Hash 计算 SHA-256 哈希值(string 版本)

func SHA256HashBytes added in v3.1.16

func SHA256HashBytes(data []byte) string

SHA256HashBytes 计算 SHA-256 哈希值([]byte 版本)

func SaveConfigFile

func SaveConfigFile(conf map[string]any) error

func StatusMessage

func StatusMessage(status int) string

StatusMessage returns the correct message for the provided HTTP statuscode

func ToAny

func ToAny[T any](items []T) []any

ToAny 把任意类型切片转换成 []any

e.g: core.ToAny(uuids)

func ToNamer added in v3.1.10

func ToNamer(name string) string

func ToStrings

func ToStrings[T fmt.Stringer](items []T) []string

ToStrings 把任意实现了 fmt.Stringer 的类型切片转换成 []string

e.g: core.ToStrings(uuids)

func ToStringsFromAny

func ToStringsFromAny(items []any) []string

ToStringsFromAny 把 []any 转换成 []string

func Unique added in v3.1.10

func Unique[S ~[]E, E comparable](s S) S

Unique 去重

uniqueScopes := core.Unique(scopes)

func Warn

func Warn(f string, args ...any)

warning logger

func WithTransaction

func WithTransaction(tx *DB, fn func(tx *DB) error) error

WithTransaction

func (s *TypeX) WithTransaction(fn func(tx *core.DB) error) error {
	return WithTransaction(s.DB, fn)
}

Types

type Array

type Array []any

Array 数组类型

func ParseAndDeduplicate

func ParseAndDeduplicate(s string) Array

ParseAndDeduplicate 将输入字符串按逗号分割,去除空字段及重复值

func (Array) FindHandle

func (d Array) FindHandle(handle, value string) Map

func (Array) GormDataType

func (Array) GormDataType() string

GormDataType schema.Field DataType

func (Array) MarshalBinary

func (d Array) MarshalBinary() (data []byte, err error)

func (*Array) Scan

func (d *Array) Scan(src any) error

Scan 数据驱动接口

func (Array) String

func (d Array) String() []string

Strings 转换为 []string

func (Array) StringsJoin

func (d Array) StringsJoin(sp string) string

StringsJoin 链接为字符串

func (*Array) UnmarshalBinary

func (d *Array) UnmarshalBinary(data []byte) error

func (Array) Value

func (d Array) Value() (driver.Value, error)

Value 数据驱动接口

type BaseCtx

type BaseCtx struct {
	W ResponseWriter
	R *http.Request
	// contains filtered or unexported fields
}

func (*BaseCtx) Abort

func (c *BaseCtx) Abort(args ...any) Ctx

func (*BaseCtx) Accepts

func (c *BaseCtx) Accepts(offers ...string) string

Accepts checks if the specified extensions or content types are acceptable.

func (*BaseCtx) AcceptsCharsets

func (c *BaseCtx) AcceptsCharsets(offers ...string) string

AcceptsCharsets checks if the specified charset is acceptable.

func (*BaseCtx) AcceptsEncodings

func (c *BaseCtx) AcceptsEncodings(offers ...string) string

AcceptsEncodings checks if the specified encoding is acceptable.

func (*BaseCtx) AcceptsLanguages

func (c *BaseCtx) AcceptsLanguages(offers ...string) string

AcceptsLanguages checks if the specified language is acceptable.

func (*BaseCtx) Append

func (c *BaseCtx) Append(key string, values ...string) Ctx

Append values to the same key, separated by commas

c.Append("Vary", "Accept-Encoding", "Accept", "X-Requested-With")

Response Header:

Vary: Accept-Encoding, Accept, X-Requested-With

func (*BaseCtx) Bind added in v3.1.8

func (c *BaseCtx) Bind(out any, debug ...bool) error

func (*BaseCtx) BodyParser

func (c *BaseCtx) BodyParser(out any) error

BodyParser parses the request body into the provided 'out' parameter. It delegates the actual parsing to the ReadBody method.

func (*BaseCtx) Context added in v3.1.6

func (c *BaseCtx) Context() context.Context

func (*BaseCtx) Cookie

func (c *BaseCtx) Cookie(cookie *http.Cookie)

Cookie sets a cookie by passing a cookie struct.

func (*BaseCtx) Cookies

func (c *BaseCtx) Cookies(name string) (string, error)

Cookie returns the named cookie provided in the request or ErrNoCookie if not found. And return the named cookie is unescaped. If multiple cookies match the given name, only one cookie will be returned.

func (*BaseCtx) Core

func (c *BaseCtx) Core() *Core

Core implements Ctx.

func (*BaseCtx) Ctx added in v3.1.8

func (c *BaseCtx) Ctx() context.Context

func (*BaseCtx) File

func (c *BaseCtx) File(filePath string)

File implements Ctx.

func (*BaseCtx) FileAttachment

func (c *BaseCtx) FileAttachment(filepath, filename string)

FileAttachment writes the specified file into the body stream in an efficient way On the client side, the file will typically be downloaded with the given filename

func (*BaseCtx) FileFromFS

func (c *BaseCtx) FileFromFS(filepath string, fs http.FileSystem)

FileFromFS writes the specified file from http.FileSystem into the body stream in an efficient way.

func (*BaseCtx) Flush

func (c *BaseCtx) Flush(data any, statusCode ...int) error

Flush response dat and break

func (*BaseCtx) FormFile

func (c *BaseCtx) FormFile(key string) (*multipart.FileHeader, error)

FormFile returns the first file for the provided form key. FormFile calls ParseMultipartForm and ParseForm if necessary.

func (*BaseCtx) FormValue

func (c *BaseCtx) FormValue(key string, def ...string) string

FormValue support old version

func (*BaseCtx) FormValues

func (c *BaseCtx) FormValues(key string, def ...[]string) []string

FormValues returns a slice of strings for a given query key.

func (*BaseCtx) Format

func (c *BaseCtx) Format(body any) error

Format performs content-negotiation on the Accept HTTP header. It uses Accepts to select a proper format. If the header is not specified or there is no proper format, text/plain is used.

func (*BaseCtx) FromValueInt

func (c *BaseCtx) FromValueInt(key string, def ...int) int

func (*BaseCtx) FromValueUUID

func (c *BaseCtx) FromValueUUID(key string, def ...UUID) UUID

func (*BaseCtx) FromValueUid

func (c *BaseCtx) FromValueUid(key string, def ...uid.UID) uid.UID

func (*BaseCtx) FromValueXid added in v3.1.3

func (c *BaseCtx) FromValueXid(key string, def ...xid.ID) xid.ID

func (*BaseCtx) Get

func (c *BaseCtx) Get(key string) (val any, ok bool)

Get returns the value for the given key, ie: (value, true). If the value does not exists it returns (nil, false)

func (*BaseCtx) GetAs

func (c *BaseCtx) GetAs(key string, v any) error

GetAs retrieve struct like c.Get("user").(User)

> Experimental function, problem unknown

func (*BaseCtx) GetBool

func (c *BaseCtx) GetBool(key string) (value bool)

GetBool returns the value associated with the key as a boolean.

func (*BaseCtx) GetDuration

func (c *BaseCtx) GetDuration(key string) (d time.Duration)

GetDuration returns the value associated with the key as a duration.

func (*BaseCtx) GetFloat64

func (c *BaseCtx) GetFloat64(key string, def ...float64) (value float64)

GetFloat64 returns the value associated with the key as a float64.

func (*BaseCtx) GetHeader

func (c *BaseCtx) GetHeader(key string, defaultValue ...string) string

GetHeader get Request header

func (*BaseCtx) GetInt

func (c *BaseCtx) GetInt(key string, def ...int) (i int)

GetInt returns the value associated with the key as an integer.

func (*BaseCtx) GetInt64

func (c *BaseCtx) GetInt64(key string, def ...int64) (i int64)

GetInt64 returns the value associated with the key as an integer.

func (*BaseCtx) GetMap

func (c *BaseCtx) GetMap(key string, def ...map[string]any) (value map[string]any)

GetMap returns the value associated with the key as a map of interfaces.

> return map[string]any

func (*BaseCtx) GetMapString

func (c *BaseCtx) GetMapString(key string, def ...map[string]string) (value map[string]string)

GetMapString returns the value associated with the key as a map of strings.

> return map[string]string

func (*BaseCtx) GetMapStringSlice

func (c *BaseCtx) GetMapStringSlice(key string, def ...map[string][]string) (value map[string][]string)

GetStringMapStringSlice returns the value associated with the key as a map to a slice of strings.

> return map[string][]string

func (*BaseCtx) GetParamInt

func (c *BaseCtx) GetParamInt(key string, defaultValue ...int) (int, error)

GetParamInt get int param, return -1 if failed

func (*BaseCtx) GetParamSid added in v3.0.7

func (c *BaseCtx) GetParamSid(key string, defaultValue ...sid.ID) (sid.ID, error)

func (*BaseCtx) GetParamUid

func (c *BaseCtx) GetParamUid(key string, defaultValue ...uid.UID) (uid.UID, error)

GetParamUid get uid.UID param, return uid.Nil if failed

func (*BaseCtx) GetSid added in v3.1.4

func (c *BaseCtx) GetSid(key string, def ...sid.ID) (v sid.ID)

func (*BaseCtx) GetStatus

func (c *BaseCtx) GetStatus() int

GetStatus get response statusCode

func (*BaseCtx) GetString

func (c *BaseCtx) GetString(key string, def ...string) (value string)

GetString returns the value associated with the key as a string.

func (*BaseCtx) GetStrings

func (c *BaseCtx) GetStrings(key string, def ...[]string) (value []string)

GetStrings String Slice returns the value associated with the key as a slice of strings.

func (*BaseCtx) GetTime

func (c *BaseCtx) GetTime(key string) (t time.Time)

GetTime returns the value associated with the key as time.

func (*BaseCtx) GetUUID

func (c *BaseCtx) GetUUID(key string, def ...UUID) (v UUID)

func (*BaseCtx) GetUint

func (c *BaseCtx) GetUint(key string, def ...uint) (i uint)

GetUint returns the value associated with the key as an integer.

func (*BaseCtx) GetUint64

func (c *BaseCtx) GetUint64(key string, def ...uint64) (i uint64)

GetUint64 returns the value associated with the key as an integer.

func (*BaseCtx) GetXid added in v3.1.3

func (c *BaseCtx) GetXid(key string, def ...xid.ID) (v xid.ID)

func (*BaseCtx) Host added in v3.1.10

func (c *BaseCtx) Host() string

func (*BaseCtx) JSON

func (c *BaseCtx) JSON(data any, code ...int) error

func (*BaseCtx) JSONP

func (c *BaseCtx) JSONP(data any, callback ...string) error

func (*BaseCtx) Locals added in v3.1.10

func (c *BaseCtx) Locals(key string, val ...any) any

func (*BaseCtx) Method

func (c *BaseCtx) Method() string

func (*BaseCtx) Next

func (c *BaseCtx) Next() error

func (*BaseCtx) Param added in v3.1.17

func (c *BaseCtx) Param(key string, defaultValue ...string) string

func (*BaseCtx) ParamUUID

func (c *BaseCtx) ParamUUID(key string, defaultValue ...UUID) UUID

func (*BaseCtx) Params

func (c *BaseCtx) Params(key string, defaultValue ...string) string

func (*BaseCtx) ParamsInt

func (c *BaseCtx) ParamsInt(key string, defaultValue ...int) (int, error)

ParamsInt get int param, return -1 if failed

func (*BaseCtx) ParamsMaps added in v3.1.10

func (c *BaseCtx) ParamsMaps() map[string]string

func (*BaseCtx) ParamsSid added in v3.0.7

func (c *BaseCtx) ParamsSid(key string, defaultValue ...sid.ID) (sid.ID, error)

func (*BaseCtx) ParamsUid

func (c *BaseCtx) ParamsUid(key string, defaultValue ...uid.UID) (uid.UID, error)

ParamsUid get uid.UID param, return uid.Nil if failed

func (*BaseCtx) ParamsUuid

func (c *BaseCtx) ParamsUuid(key string, defaultValue ...UUID) (UUID, error)

ParamsUid get uid.UID param, return uid.Nil if failed

func (*BaseCtx) ParamsXid added in v3.1.3

func (c *BaseCtx) ParamsXid(key string, defaultValue ...xid.ID) (xid.ID, error)

func (*BaseCtx) Path

func (c *BaseCtx) Path() string

func (*BaseCtx) Query

func (c *BaseCtx) Query(key string, def ...string) string

FormValue Get query

key string
def string default val optional

> GET /?name=Jack&id=

`
  name := c.FormValue("name")  // name = Jack
  id := c.FormValue("id", "1") // id = 1 Because the default value is used
`

func (*BaseCtx) QueryInt

func (c *BaseCtx) QueryInt(key string, def ...int) int

func (*BaseCtx) Querys

func (c *BaseCtx) Querys(key string, def ...[]string) []string

func (*BaseCtx) ReadBody

func (c *BaseCtx) ReadBody(out any, debug ...bool) error

多文件

type Upload struct {
    Files []*multipart.FileHeader `form:"files"`
}

func (*BaseCtx) Redirect

func (c *BaseCtx) Redirect(to string, stCode ...int) error

func (*BaseCtx) RedirectJS

func (c *BaseCtx) RedirectJS(to string, msg ...string)

func (*BaseCtx) RemoteIP

func (c *BaseCtx) RemoteIP() net.IP

RemoteIP parses the IP from Request.RemoteAddr, normalizes and returns the IP (without the port). It also checks if the remoteIP is a trusted proxy or not. In order to perform this validation, it will see if the IP is contained within at least one of the CIDR blocks

func (*BaseCtx) RemoveCookie

func (c *BaseCtx) RemoveCookie(name, path string, dom ...string)

func (*BaseCtx) Render

func (c *BaseCtx) Render(f string, bind ...any) error

func (*BaseCtx) Request

func (c *BaseCtx) Request() *http.Request

Request implements Ctx.

func (*BaseCtx) Response

func (c *BaseCtx) Response() ResponseWriter

ResponseWriter implements Ctx.

func (*BaseCtx) SaveFile

func (c *BaseCtx) SaveFile(key, dst string, args ...any) (relpath, abspath string, err error)

SaveFile upload file save to a folder

path = {root}/{dst}/{id}
@param
name string filename
dst string dst path
root string root path optional
id   path optional type uid.UID, int, uint, int64,uint64
rename bool optional
return relPath, absPath

   c.SaveFile("file", "/images")
   (string) relpath "/images/10/favicon.png"
   (string) abspath "/images/10/favicon.png"

   c.SaveFile("file", "/images", "./static")
   (string) relpath "/images/10/5hsbkthaadld/favicon.png"
   (string) abspath "/static/images/10/5hsbkthaadld/favicon.png"

   c.SaveFile("file", "/images", "./static", uid.New())
   (string) relpath "/images/10/5hsbkthaadld/5hsbkthaadld.png"
   (string) abspath "/static/images/10/5hsbkthaadld/5hsbkthaadld.png"
              👇file    👇dst      👇root     👇id      👇rename
   c.SaveFile("file", "/images", "./static", uid.New(), true)
   (string) relpath "/images/10/5hsbkthaadld/5hsbkthaadld.png"
   (string) abspath "/static/images/10/5hsbkthaadld/5hsbkthaadld.png"

func (*BaseCtx) SaveFiles

func (c *BaseCtx) SaveFiles(key, dst string, args ...any) (rel Array, err error)

SaveFiles like SaveFile

@params key string MultipartForm key name : files dst string static to ./static more args see SaveFile

rel, err := c.SaveFiles("files", "static", true)

return relative url path rel is

return []string {
	"/static/09/wjejwifx.jpg",
	"/static/09/wjejwifx.jpg",
	"/static/09/wjejwifx.jpg",
}

func (*BaseCtx) Send

func (c *BaseCtx) Send(buf []byte) error

Send send []byte to client

func (*BaseCtx) SendStatus

func (c *BaseCtx) SendStatus(code int, msg ...string) error

func (*BaseCtx) SendString

func (c *BaseCtx) SendString(str ...any) error

func (*BaseCtx) Set

func (c *BaseCtx) Set(key string, val any)

set locals var

func (*BaseCtx) SetCookie

func (c *BaseCtx) SetCookie(name, value string, exp time.Time, path string, args ...any)

SetCookie adds a Set-Cookie header to the ResponseWriter's headers. The provided cookie must have a valid Name. Invalid cookies may be silently dropped.

func (*BaseCtx) SetHeader

func (c *BaseCtx) SetHeader(key string, value string)

func (*BaseCtx) SetParams

func (c *BaseCtx) SetParams(key, val string)

func (*BaseCtx) StartAt

func (c *BaseCtx) StartAt(t ...time.Time) time.Time

func (*BaseCtx) Status

func (c *BaseCtx) Status(code int) Ctx

func (*BaseCtx) Stream

func (c *BaseCtx) Stream(step func(w io.Writer) bool) bool

Stream sends a streaming response and returns a boolean indicates "Is client disconnected in middle of stream"

func (*BaseCtx) TextBytes

func (c *BaseCtx) TextBytes(out io.Writer, f string, bind ...any) error

func (*BaseCtx) TextRender

func (c *BaseCtx) TextRender(f string, bind ...any) error

func (*BaseCtx) ToJSON

func (c *BaseCtx) ToJSON(data any, msg ...any) error

func (*BaseCtx) ToJSONCode

func (c *BaseCtx) ToJSONCode(data any, msg ...any) error

func (*BaseCtx) Type

func (c *BaseCtx) Type(extension string, charset ...string) Ctx

Type sets the Content-Type HTTP header to the MIME type specified by the file extension.

func (*BaseCtx) Validate

func (c *BaseCtx) Validate(out any) error

Validate 验证传入的结构体

func (*BaseCtx) Vars

func (c *BaseCtx) Vars() Map

func (*BaseCtx) Vary

func (c *BaseCtx) Vary(fields ...string) Ctx

Vary add the given header field to the vary response header

c.Vary("Accept-Encoding", "Accept", "X-Requested-With")

Response Header:

Vary: Accept-Encoding, Accept, X-Requested-With

func (*BaseCtx) ViewReload

func (c *BaseCtx) ViewReload()

func (*BaseCtx) ViewTheme

func (c *BaseCtx) ViewTheme(theme string)

ViewTheme 使用模版风格

func (*BaseCtx) XML

func (c *BaseCtx) XML(data any) error

XML converts any interface or string to XML. This method also sets the content header to application/xml.

type CertMagicConfig added in v3.1.10

type CertMagicConfig struct {
	APIToken string
	Email    string
	Domains  []string
	CacheDir string
}

type ClientInfo added in v3.1.10

type ClientInfo struct {
	IP string
	UA string
}

func ExtractClientInfo added in v3.1.10

func ExtractClientInfo(ctx context.Context) *ClientInfo

type Constraint

type Constraint struct {
	ID            TypeConstraint
	RegexCompiler *regexp.Regexp
	Data          []string
}

func (*Constraint) CheckConstraint

func (c *Constraint) CheckConstraint(param string) bool

type Core

type Core struct {
	*http.Server

	Conf Options

	Debug bool

	RequestMethods []string

	ErrorHandler ErrorHandler

	Ctx context.Context

	MaxMultipartMemory int64

	Views      view.IEngine
	TextEngine view.ITextEngine

	EtcdDiscovery *etcd.Discovery
	// contains filtered or unexported fields
}

func New

func New(options ...Options) *Core

func (*Core) ALL

func (app *Core) ALL(path string, handler any, middleware ...any) Router

func (*Core) AcquireCtx

func (app *Core) AcquireCtx(w http.ResponseWriter, r *http.Request) *BaseCtx

func (*Core) Add

func (app *Core) Add(methods []string, path string, handler any, middleware ...any) Router

func (*Core) AddHandle

func (app *Core) AddHandle(methods []string, uri string, group *Group, handler any, middleware ...HandlerFunc) Router

core.go - AddHandle 方法

func (*Core) CONNECT

func (app *Core) CONNECT(path string, handler any, middleware ...any) Router

func (*Core) DELETE

func (app *Core) DELETE(path string, handler any, middleware ...any) Router

func (*Core) EnableEtcdDiscovery added in v3.1.10

func (app *Core) EnableEtcdDiscovery(opts *etcd.Options) error

EnableEtcdDiscovery 启用 etcd 服务发现

func (*Core) EnableEtcdRegistry added in v3.1.10

func (app *Core) EnableEtcdRegistry(opts *etcd.Options) error

EnableEtcdRegistry 启用 etcd 服务注册 当 opts 为 nil 时,从配置文件读取;当 opts 已设置字段时,保留用户值

func (*Core) EnableGRPC added in v3.1.10

func (app *Core) EnableGRPC(addr ...string) *Core

EnableGRPC 启用 gRPC 支持

func (*Core) ErrGroup added in v3.1.10

func (app *Core) ErrGroup() *errgroup.Group

func (*Core) GET

func (app *Core) GET(path string, handler any, middleware ...any) Router

func (*Core) GetGRPCServer added in v3.1.10

func (app *Core) GetGRPCServer() *grpc.Server

GetGRPCServer 获取 gRPC 服务器实例(用于注册服务)

func (*Core) GetModule

func (app *Core) GetModule(id string) (ModuleInfo, error)

func (*Core) Group

func (app *Core) Group(prefix string, handlers ...HandlerFuncs) Router

func (*Core) GrpcClient added in v3.1.10

func (app *Core) GrpcClient(serviceName string, opts ...grpc.DialOption) (*grpc.ClientConn, error)

GrpcClient 创建 gRPC 客户端连接(基于 etcd 服务发现)

func (*Core) HEAD

func (app *Core) HEAD(path string, handler any, middleware ...any) Router

func (*Core) Listen

func (app *Core) Listen(port ...any) error

func (*Core) MustGrpcClient added in v3.1.13

func (app *Core) MustGrpcClient(serviceName string, opts ...grpc.DialOption) *grpc.ClientConn

MustGrpcClient 创建 gRPC 客户端连接,失败则 panic

func (*Core) OPTIONS

func (app *Core) OPTIONS(path string, handler any, middleware ...any) Router

func (*Core) OnShutdown added in v3.1.10

func (app *Core) OnShutdown(fn func())

OnShutdown 添加关闭钩子

func (*Core) PATCH

func (app *Core) PATCH(path string, handler any, middleware ...any) Router

func (*Core) POST

func (app *Core) POST(path string, handler any, middleware ...any) Router

func (*Core) PUT

func (app *Core) PUT(path string, handler any, middleware ...any) Router

func (*Core) ProcessedHandler added in v3.1.11

func (app *Core) ProcessedHandler(hand any) HandlerFuncs

func (*Core) RegisterGRPCService added in v3.1.10

func (app *Core) RegisterGRPCService(registerFunc func(*grpc.Server))

RegisterGRPCService 注册 gRPC 服务

func (*Core) ReleaseCtx

func (app *Core) ReleaseCtx(c Ctx)

func (*Core) RemoveHandle added in v3.1.17

func (app *Core) RemoveHandle(methods []string, uri string)

func (*Core) Run

func (app *Core) Run(port ...any) error

Run 启动应用程序并监听指定端口 参数 port 是可选的端口号,可以是一个或多个值 返回可能发生的错误

func (*Core) Serve

func (app *Core) Serve(ln net.Listener) error

func (*Core) ServeHTTP

func (app *Core) ServeHTTP(w http.ResponseWriter, r *http.Request)

func (*Core) Static

func (app *Core) Static(relativePath, root string) Router

func (*Core) StaticFS

func (app *Core) StaticFS(relativePath string, fs http.FileSystem) Router

func (*Core) StaticFile

func (app *Core) StaticFile(relativePath, dirname string) Router

StaticFile static file

app.StaticFile("/favicon.ico", "./favicon.ico")

func (*Core) StaticFileFS

func (app *Core) StaticFileFS(relativePath, dirname string, fs http.FileSystem) Router

StaticFileFS works just like `StaticFile` but a custom `http.FileSystem` can be used instead..

app.StaticFileFS("favicon.ico", "./resources/favicon.ico", Dir{".", false})

func (*Core) TRACE

func (app *Core) TRACE(path string, handler any, middleware ...any) Router

func (*Core) Use

func (app *Core) Use(fn ...any) Router

type Ctx

type Ctx interface {
	Context() context.Context // Request().Context()
	Ctx() context.Context
	Host() string
	Response() ResponseWriter                                              // Response() return http.ResponseWriter
	Request() *http.Request                                                // Request() return *http.Request
	RedirectJS(to string, msg ...string)                                   // use js redirect
	Redirect(to string, stCode ...int) error                               // base redirect
	RemoteIP() net.IP                                                      // remote client ip
	SetCookie(name, value string, exp time.Time, path string, args ...any) // set cookie
	RemoveCookie(name, path string, dom ...string)                         // remove some cookie
	Cookie(cookie *http.Cookie)                                            // set cookie with cookie object
	Cookies(name string) (string, error)                                   // get some cookie
	ReadBody(out any, debug ...bool) error                                 // read put post any request body to struct or map
	Bind(out any, debug ...bool) error                                     // ReadBody alias  read put post form data to struct or map
	BodyParser(out any) error                                              // read put post form data to struct or map
	Validate(out any) error                                                // validate struct or map
	Next() error                                                           // next HandlerFunc
	Path() string                                                          // return http.Request.URI.path

	Send(buf []byte) error                               // send []byte data
	SendString(msg ...any) error                         // send string to body
	SendStatus(code int, msg ...string) error            // send status to client, options msg with display
	SetHeader(key string, value string)                  // set response header
	GetHeader(key string, defaultValue ...string) string // get request header
	Method() string                                      // return method e.g: GET,POST,PUT,DELETE,OPTION,HEAD...
	GetStatus() int                                      // get response status
	Status(code int) Ctx                                 // set response status
	Core() *Core                                         // return app(*Core)
	Abort(args ...any) Ctx                               // Deprecated: As of v2.0.0, this function simply calls Ctx.Format.
	JSON(any, ...int) error                              // send json
	JSONP(data any, callback ...string) error            // send jsonp
	ToJSON(data any, msg ...any) error                   // send json with status
	ToJSONCode(data any, msg ...any) error               // send have code to json
	StartAt(t ...time.Time) time.Time                    // set ctx start time if t set, else get start at
	ParamsMaps() map[string]string
	Params(key string, defaultValue ...string) string                           // get Params data e.g c.Params("param")
	Param(key string, defaultValue ...string) string                            // get Param data e.g c.Param("param")
	ParamsUid(key string, defaultValue ...uid.UID) (uid.UID, error)             // get Param UID type, return uid.Nil if failed
	GetParamSid(key string, defaultValue ...sid.ID) (sid.ID, error)             // get Param ID type, return sid.Nil if failed
	ParamsSid(key string, defaultValue ...sid.ID) (sid.ID, error)               // get Param ID type, return sid.Nil if failed
	ParamsXid(key string, defaultValue ...xid.ID) (xid.ID, error)               // get Param XID type, return xid.Nil if failed
	ParamsUuid(key string, defaultValue ...UUID) (UUID, error)                  // get Param UID type, return uid.Nil if failed
	ParamUUID(key string, defaultValue ...UUID) UUID                            // get Param UUID type, return uid.Nil if failed
	ParamsInt(key string, defaultValue ...int) (int, error)                     // get Param int type, return -1 if failed
	GetParamUid(key string, defaultValue ...uid.UID) (uid.UID, error)           // get param uid.UID, return uid.Nil if failed
	GetParamInt(key string, defaultValue ...int) (int, error)                   // get param int, return -1 if failed
	File(filePath string)                                                       // send file
	FileAttachment(filepath, filename string)                                   // send file attachment
	FileFromFS(filePath string, fs http.FileSystem)                             // send file from FS
	Append(key string, values ...string) Ctx                                    // append response header
	Vary(fields ...string) Ctx                                                  // set response vary
	FormFile(key string) (*multipart.FileHeader, error)                         // get form file
	SaveFile(key, dst string, args ...any) (relpath, abspath string, err error) // upload some one file
	SaveFiles(key, dst string, args ...any) (rel Array, err error)              // upload multi-file
	Query(key string, def ...string) string                                     // get request query string like ?id=12345
	QueryInt(key string, def ...int) int                                        // parse form value to int
	Querys(key string, def ...[]string) []string                                // like query, but return []string values

	FromValueXid(key string, def ...xid.ID) xid.ID   // parse form value to xid
	FormValue(key string, def ...string) string      // like Query support old version
	FromValueInt(key string, def ...int) int         // parse form value to int
	FromValueUid(key string, def ...uid.UID) uid.UID // parse form value to uid
	FromValueUUID(key string, def ...UUID) UUID      // parse form value to uuid
	FormValues(key string, def ...[]string) []string // like Querys
	Flush(data any, statusCode ...int) error         // flush
	Accepts(offers ...string) string                 // Accepts checks if the specified extensions or content types are acceptable.
	AcceptsCharsets(offers ...string) string         // AcceptsCharsets checks if the specified charset is acceptable.
	AcceptsEncodings(offers ...string) string        // AcceptsEncodings checks if the specified encoding is acceptable.
	AcceptsLanguages(offers ...string) string        // AcceptsLanguages checks if the specified language is acceptable.
	Format(body any) error                           // Format performs content-negotiation on the Accept HTTP header. It uses Accepts to select a proper format. If the header is not specified or there is no proper format, text/plain is used.
	Type(extension string, charset ...string) Ctx    // 发送 response content-type
	XML(data any) error                              // output xml
	Set(key string, val any)
	Get(key string) (val any, ok bool)
	Locals(key string, val ...any) any // set get local ver
	GetString(key string, def ...string) (value string)
	GetBool(key string) (value bool)
	GetInt(key string, def ...int) (i int)
	GetInt64(key string, def ...int64) (i int64)
	GetUint(key string, def ...uint) (i uint)
	GetUint64(key string, def ...uint64) (i uint64)
	GetUUID(key string, def ...UUID) (v UUID)
	GetXid(key string, def ...xid.ID) (v xid.ID)
	GetSid(key string, def ...sid.ID) (v sid.ID)
	GetFloat64(key string, def ...float64) (value float64)
	GetTime(key string) (t time.Time)
	GetDuration(key string) (d time.Duration)
	GetStrings(key string, def ...[]string) (value []string)
	GetMap(key string, def ...map[string]any) (value map[string]any)
	GetMapString(key string, def ...map[string]string) (value map[string]string)
	GetMapStringSlice(key string, def ...map[string][]string) (value map[string][]string)
	GetAs(key string, v any) error
	Vars() Map
	Stream(step func(w io.Writer) bool) bool
	ViewReload() // set view reload
	Render(f string, bind ...any) error
	TextBytes(out io.Writer, f string, bind ...any) error
	TextRender(f string, bind ...any) error
	SetParams(key string, val string)
	// contains filtered or unexported methods
}

type DB

type DB = gorm.DB

func Conn

func Conn(name ...string) *DB

func Where

func Where(whr *Map, db ...*DB) (*DB, int, int)

Where build page query

whr *Map
db  *DB optional
return *DB, pos, lmt

type Date

type Date struct {
	time.Time
}

func (Date) MarshalJSON

func (d Date) MarshalJSON() ([]byte, error)

func (*Date) Scan

func (d *Date) Scan(value any) error

func (Date) String

func (d Date) String() string

func (*Date) UnmarshalJSON

func (d *Date) UnmarshalJSON(b []byte) error

func (Date) Value

func (d Date) Value() (driver.Value, error)

type Enum

type Enum interface {
	~uint8
}

type Error

type Error struct {
	// contains filtered or unexported fields
}

func NewError

func NewError(code int, args ...any) *Error

func (*Error) Code

func (e *Error) Code() int

Code 实现 自定义接口,返回业务错误码

func (*Error) Error

func (e *Error) Error() string

Error 实现 error 接口

func (*Error) Errors

func (e *Error) Errors() (int, string)

Errors 实现自定义接口,返回业务错误码和消息

func (*Error) GRPCStatus added in v3.1.16

func (e *Error) GRPCStatus() *status.Status

GRPCStatus 实现 gRPC 状态接口,让 status.FromError 能正常工作

func (*Error) Unwrap added in v3.1.16

func (e *Error) Unwrap() error

type ErrorHandler

type ErrorHandler func(Ctx, error) error

type Errors

type Errors interface {
	Error() string
	Errors() (int, string)
	Code() int
}

type EventData

type EventData struct {
	Event string `json:"event"`
	Data  any    `json:"data"`
}

func (EventData) String

func (h EventData) String() string

func (*EventData) ToString

func (h *EventData) ToString() string

type EventHub

type EventHub struct {
	// contains filtered or unexported fields
}

func NewEventHub

func NewEventHub(interval ...time.Duration) *EventHub

func (*EventHub) Broadcast

func (h *EventHub) Broadcast(data EventData)

func (*EventHub) Get

func (h *EventHub) Get(c Ctx)

func (*EventHub) PostData

func (h *EventHub) PostData(c Ctx)

func (*EventHub) Register

func (h *EventHub) Register(c chan EventData)

func (*EventHub) UnRegister

func (h *EventHub) UnRegister(c chan EventData)

type Group

type Group struct {
	*Core

	Prefix string
	// contains filtered or unexported fields
}

func (*Group) ALL

func (g *Group) ALL(path string, handler any, middleware ...any) Router

func (*Group) Add

func (g *Group) Add(methods []string, path string, handler any, middleware ...any) Router

Add allows you to specify multiple HTTP methods to register a route.

func (*Group) CONNECT

func (g *Group) CONNECT(path string, handler any, middleware ...any) Router

func (*Group) DELETE

func (g *Group) DELETE(path string, handler any, middleware ...any) Router

func (*Group) GET

func (g *Group) GET(path string, handler any, middleware ...any) Router

Get registers a route for GET methods that requests a representation of the specified resource. Requests using GET should only retrieve data.

func (*Group) Group

func (g *Group) Group(prefix string, handlers ...HandlerFuncs) Router

func (*Group) HEAD

func (g *Group) HEAD(path string, handler any, middleware ...any) Router

func (*Group) Name

func (g *Group) Name(name string) Router

func (*Group) OPTIONS

func (g *Group) OPTIONS(path string, handler any, middleware ...any) Router

func (*Group) PATCH

func (g *Group) PATCH(path string, handler any, middleware ...any) Router

func (*Group) POST

func (g *Group) POST(path string, handler any, middleware ...any) Router

func (*Group) PUT

func (g *Group) PUT(path string, handler any, middleware ...any) Router

func (*Group) TRACE

func (g *Group) TRACE(path string, handler any, middleware ...any) Router

func (*Group) Use

func (g *Group) Use(fn ...any) Router

Use registers a middleware route that will match requests with the provided prefix (which is optional and defaults to "/"). Also, you can pass another app instance as a sub-router along a routing path. It's very useful to split up a large API as many independent routers and compose them as a single service using Use. The core error handler and any of the core sub apps are added to the application's error handlers to be invoked on errors that happen within the prefix route.

	app.Use(func(c core.Ctx) error {
	     return c.Next()
	})
	app.Use("/api", func(c core.Ctx) error {
	     return c.Next()
	})
	app.Use("/api", handler, func(c core.Ctx) error {
	     return c.Next()
	})
 	subApp := core.New()
	app.Use("/mounted-path", subApp)

This method will match all HTTP verbs: GET, POST, PUT, HEAD etc...

type Handler

type Handler struct {
	Handlers map[string]any // record callable handle

	ID string
	// contains filtered or unexported fields
}

func (*Handler) Core

func (h *Handler) Core(app ...*Core) *Core

func (*Handler) Debug added in v3.1.8

func (h *Handler) Debug() bool

func (*Handler) HandName

func (h *Handler) HandName(name ...string) string

func (*Handler) Init

func (h *Handler) Init()

func (*Handler) Prefix

func (h *Handler) Prefix(prefix ...string) string

func (*Handler) Preload

func (h *Handler) Preload(c Ctx) error

func (*Handler) PushHandler

func (h *Handler) PushHandler(method, path string)

type HandlerFun

type HandlerFun = func(Ctx)

type HandlerFunc

type HandlerFunc = func(Ctx) error

func CustomRecoveryWithWriter

func CustomRecoveryWithWriter(out io.Writer, handle RecoveryFunc) HandlerFunc

CustomRecoveryWithWriter returns a middleware for a given writer that recovers from any panics and calls the provided handle func to handle it.

func Logger

func Logger(conf ...LoggerConfig) HandlerFunc

func Recovery

func Recovery() HandlerFunc

Recovery returns a middleware that recovers from any panics and writes a 500 if there was one.

func RecoveryWithWriter

func RecoveryWithWriter(out io.Writer, recovery ...RecoveryFunc) HandlerFunc

RecoveryWithWriter returns a middleware for a given writer that recovers from any panics and writes a 500 if there was one.

type HandlerFuncs

type HandlerFuncs []HandlerFunc

type HandlerNormal

type HandlerNormal = func(w http.ResponseWriter, r *http.Request)

type HasUUID

type HasUUID interface {
	GetUUID() UUID
}

type HookWriter

type HookWriter struct {
	Writer  io.Writer
	Monitor *LogMonitor
}

func (*HookWriter) Write

func (h *HookWriter) Write(p []byte) (n int, err error)

type IModel added in v3.0.7

type IModel struct {
	ID        IntID           `gorm:"primarykey;autoIncrement:false;comment:主键" json:"id,omitzero"`
	CreatedAt *time.Time      `gorm:"<-:create;comment:创建时间" json:"created_at,omitempty"`
	UpdatedAt *time.Time      `gorm:"autoUpdateTime;comment:更新时间" json:"updated_at,omitempty"`
	DeletedAt *gorm.DeletedAt `gorm:"index;comment:删除时间" json:"deleted_at,omitempty"`
}

type Int

type Int int64

func (Int) GormDataType

func (Int) GormDataType() string

GormDataType schema.Field DataType

func (Int) Int

func (m Int) Int() int

转换结果为标准的 int

func (Int) Int64

func (m Int) Int64() int64

转换结果为标准的 int64

func (*Int) UnmarshalJSON

func (m *Int) UnmarshalJSON(data []byte) error

type IntID added in v3.0.7

type IntID uint

func (*IntID) Encode added in v3.0.7

func (id *IntID) Encode() string

func (*IntID) Scan added in v3.0.7

func (id *IntID) Scan(value any) error

func (IntID) Value added in v3.0.7

func (id IntID) Value() (driver.Value, error)

type IntMoney deprecated

type IntMoney int64

Deprecated: IntMoney 已废弃,请使用 coins.Money

func IntMoneyFromRedisString

func IntMoneyFromRedisString(s string) IntMoney

Scan 实现 sql.Scanner (数据库读取时转为 IntMoney) 不做 100 倍转换

func NewIntMoneyFromFloat

func NewIntMoneyFromFloat(f float64) IntMoney

NewIntMoneyFromFloat 创建 IntMoney(内部存储分)

func ParseIntMoney

func ParseIntMoney(val any) IntMoney

ParseIntMoney 从 any 解析为 IntMoney

func (IntMoney) Abs

func (m IntMoney) Abs() IntMoney

func (IntMoney) Add

func (m IntMoney) Add(x IntMoney) IntMoney

加法

func (IntMoney) DivInt

func (m IntMoney) DivInt(n int64) IntMoney

除法

func (IntMoney) EmvAmount

func (m IntMoney) EmvAmount() string

func (IntMoney) Float64

func (m IntMoney) Float64() float64

Float64 转换为 float64 元

func (IntMoney) GormDBDataType

func (IntMoney) GormDBDataType(db *gorm.DB, field *schema.Field) string

GormDBDataType gorm 方言映射 (不同数据库可指定不同字段类型)

func (IntMoney) GormDataType

func (IntMoney) GormDataType() string

GormDataType gorm 通用数据类型 (用于生成表结构)

func (IntMoney) Int64

func (m IntMoney) Int64() int64

func (IntMoney) IsEqual

func (m IntMoney) IsEqual(x IntMoney, fraction ...int) bool

IsEqual 比较是否相等,允许指定小数位比较

func (IntMoney) MarshalBinary

func (m IntMoney) MarshalBinary() (data []byte, err error)

func (IntMoney) MarshalJSON

func (m IntMoney) MarshalJSON() ([]byte, error)

MarshalJSON 序列化

func (IntMoney) MulInt

func (m IntMoney) MulInt(n int64) IntMoney

乘法

func (*IntMoney) Scan

func (m *IntMoney) Scan(value any) error

Scan 实现 sql.Scanner (数据库读取时转为 IntMoney) 支持 int64 / float64 / string

func (IntMoney) String

func (m IntMoney) String() string

String 格式化输出

func (IntMoney) Sub

func (m IntMoney) Sub(x IntMoney) IntMoney

减法

func (IntMoney) ToFixed

func (m IntMoney) ToFixed(fraction ...int) float64

ToFixed 保留 fraction 位小数(默认 2 位)

func (*IntMoney) UnmarshalBinary

func (m *IntMoney) UnmarshalBinary(data []byte) error

func (*IntMoney) UnmarshalJSON

func (m *IntMoney) UnmarshalJSON(data []byte) error

UnmarshalJSON 反序列化

func (IntMoney) Value

func (m IntMoney) Value() (driver.Value, error)

Value 实现 driver.Valuer (写入数据库时存储为分)

type InvalidUnmarshalError

type InvalidUnmarshalError struct {
	Type reflect.Type
}

An InvalidUnmarshalError describes an invalid argument passed to Unmarshal. (The argument to Unmarshal must be a non-nil pointer.)

func (*InvalidUnmarshalError) Error

func (e *InvalidUnmarshalError) Error() string

type JSON

type JSON json.RawMessage

func (JSON) GormDBDataType

func (JSON) GormDBDataType(db *gorm.DB, field *schema.Field) string

func (JSON) GormDataType

func (JSON) GormDataType() string

GormDataType gorm common data type

func (JSON) GormValue

func (js JSON) GormValue(ctx context.Context, db *gorm.DB) clause.Expr

func (JSON) MarshalJSON

func (j JSON) MarshalJSON() ([]byte, error)

MarshalJSON to output non base64 encoded []byte

func (*JSON) Scan

func (j *JSON) Scan(value any) error

Scan scan value into Jsonb, implements sql.Scanner interface

func (JSON) String

func (j JSON) String() string

func (*JSON) UnmarshalJSON

func (j *JSON) UnmarshalJSON(b []byte) error

UnmarshalJSON to deserialize []byte

func (JSON) Value

func (j JSON) Value() (driver.Value, error)

Value return json value, implement driver.Valuer interface

type LogMonitor

type LogMonitor struct {
	// contains filtered or unexported fields
}

func NewLogMonitor

func NewLogMonitor() *LogMonitor

func (*LogMonitor) Broadcast

func (m *LogMonitor) Broadcast(msg string)

func (*LogMonitor) Register

func (m *LogMonitor) Register(c chan string)

func (*LogMonitor) UnRegister

func (m *LogMonitor) UnRegister(c chan string)

type LogRotateConfig added in v3.1.19

type LogRotateConfig struct {
	MaxSize       int64
	Daily         bool
	RetainDays    int
	Compress      bool
	CopyTruncate  bool
	DelayCompress time.Duration
	MissingOK     bool
	NotifEmpty    bool
}

func ParseLogRotateConfig added in v3.1.19

func ParseLogRotateConfig(opts ...string) (LogRotateConfig, error)

type LoggerConfig

type LoggerConfig struct {
	ForceColor bool
	Debug      bool
	Output     io.Writer
	App        *Core
}

type Map

type Map map[string]any

func (Map) Contains

func (d Map) Contains(k string) bool

func (Map) GetAs

func (d Map) GetAs(k string, v any) error

func (Map) GetBool

func (d Map) GetBool(k string) (value bool)

func (Map) GetInt

func (d Map) GetInt(k string, defaultValue ...int) (value int)

func (Map) GetString

func (d Map) GetString(k string, defaultValue ...string) (value string)

func (Map) GormDataType

func (Map) GormDataType() string

GormDataType schema.Field DataType

func (Map) MarshalBinary

func (d Map) MarshalBinary() (data []byte, err error)

func (*Map) Scan

func (d *Map) Scan(src any) error

Scan 数据驱动接口

func (Map) ToString

func (d Map) ToString(k string, def ...string) string

func (*Map) UnmarshalBinary

func (d *Map) UnmarshalBinary(data []byte) error

func (Map) UnmarshalTo

func (d Map) UnmarshalTo(k string, v any) error

func (Map) Value

func (d Map) Value() (driver.Value, error)

Value 数据驱动接口

type MethodType

type MethodType uint8
const (
	METHOD_GET MethodType = iota
	METHOD_POST
	METHOD_HEAD
	METHOD_PUT
	METHOD_DELETE
	METHOD_OPTIONS
	METHOD_CONNECT
	METHOD_TRACE
	METHOD_PATCH
	METHOD_ALL
	METHOD_USE
)

type Mod

type Mod interface {
	Init()
}

type Model

type Model struct {
	ID        uid.UID         `gorm:"size:12;primaryKey" json:"id,omitempty"`
	CreatedAt *time.Time      `json:"created_at,omitempty" gorm:"<-:create"`
	UpdatedAt *time.Time      `json:"updated_at,omitempty" gorm:"autoUpdateTime"`
	DeletedAt *gorm.DeletedAt `json:"deleted_at,omitempty" gorm:"index"`
}

func (*Model) BeforeCreate

func (m *Model) BeforeCreate(tx *DB) error

type Models

type Models struct {
	ID        UUID            `json:"id,omitzero" gorm:"size:32;primaryKey"`
	CreatedAt *time.Time      `json:"created_at,omitempty" gorm:"<-:create;comment:创建时间"`
	UpdatedAt *time.Time      `json:"updated_at,omitempty" gorm:"autoUpdateTime;comment:更新时间"`
	DeletedAt *gorm.DeletedAt `json:"deleted_at,omitempty" gorm:"index;comment:删除时间"`
}

func (*Models) BeforeCreate

func (m *Models) BeforeCreate(tx *DB) error

type Module

type Module interface {
	Init()
}

type ModuleInfo

type ModuleInfo struct {
	ID       string
	Instance func() Module
}

type Money deprecated

type Money float64

Deprecated: Money 已废弃,请使用 coins.Money

func ParseMoney

func ParseMoney(val any) Money

ParseMoney 从 any 解析为 Money

func (Money) Abs

func (m Money) Abs() Money

func (Money) AddInt

func (m Money) AddInt(in int, fraction ...int) Money

AddInt 加整数 m + in fraction in 保留小数位

func (Money) DivInt

func (m Money) DivInt(in int, fraction ...int) Money

DivInt 除以整数 m / in fraction in 保留小数位

func (Money) EmvAmount

func (m Money) EmvAmount() string

func (Money) Float64

func (m Money) Float64() float64

Float64 输出 float64

func (Money) GormDBDataType

func (Money) GormDBDataType(db *gorm.DB, field *schema.Field) string

GormDBDataType gorm 方言映射 (不同数据库可指定不同字段类型)

func (Money) Int

func (m Money) Int() Int

func (Money) IsEqual

func (m Money) IsEqual(x Money, fixed ...int) bool

func (Money) MarshalBinary added in v3.0.1

func (m Money) MarshalBinary() (data []byte, err error)

func (Money) MarshalJSON

func (m Money) MarshalJSON() ([]byte, error)

func (Money) MulInt

func (m Money) MulInt(in int, fraction ...int) Money

MulInt 乘以整数 m * in fraction in 保留小数位

func (Money) SubInt

func (m Money) SubInt(in int, fraction ...int) Money

SubInt 减整数 m - in fraction in 保留小数位

func (Money) ToFixed

func (m Money) ToFixed(fraction ...int) Money

ToFixed 保留几位小数 Param fraction int return float64

func (m Money) ToFixed(fraction ...int) Money {
	places := 2
	if len(fraction) > 0 {
		places = fraction[0]
	}
	shift := math.Pow(10, float64(places))
	fv := 0.0000000001 + float64(m) //对浮点数产生.xxx999999999 计算不准进行处理
	return Money(math.Floor(fv*shift) / shift)
}

func (Money) ToFloor

func (m Money) ToFloor(p int) Money

ToFloor 保留 p 位小数, 向下取整

func (Money) ToRound

func (m Money) ToRound(p int) Money

ToRound 保留 p 位小数,四舍五入

func (*Money) UnmarshalBinary added in v3.0.1

func (m *Money) UnmarshalBinary(data []byte) error

func (*Money) UnmarshalJSON

func (m *Money) UnmarshalJSON(data []byte) error

type NSQConsumer added in v3.1.17

type NSQConsumer struct {
	// contains filtered or unexported fields
}

NSQConsumer 封装 nsq.Consumer

func NewNSQConsumer added in v3.1.17

func NewNSQConsumer(conf NSQConsumerConfig) (*NSQConsumer, error)

NewNSQConsumer 创建 NSQ Consumer

func (*NSQConsumer) ChangeMaxInFlight added in v3.1.17

func (nc *NSQConsumer) ChangeMaxInFlight(maxInFlight int)

ChangeMaxInFlight 动态调整最大在途消息数

func (*NSQConsumer) IsStarved added in v3.1.17

func (nc *NSQConsumer) IsStarved() bool

IsStarved 判断消费者是否饥饿(可用于背压)

func (*NSQConsumer) Start added in v3.1.17

func (nc *NSQConsumer) Start(handler NSQHandlerFunc) error

Start 启动消费者(阻塞直到 Stop 或连接断开) handler 返回 nil 确认消息,返回 error 重新入队

func (*NSQConsumer) StartAsync added in v3.1.17

func (nc *NSQConsumer) StartAsync(handler NSQHandlerFunc) error

StartAsync 异步启动消费者

func (*NSQConsumer) Stats added in v3.1.17

func (nc *NSQConsumer) Stats() *nsq.ConsumerStats

Stats 获取消费者统计

func (*NSQConsumer) Stop added in v3.1.17

func (nc *NSQConsumer) Stop()

Stop 优雅停止消费者

type NSQConsumerBuilder added in v3.1.17

type NSQConsumerBuilder struct {
	// contains filtered or unexported fields
}

NSQConsumerBuilder 消费者构建器

func NewNSQConsumerBuilder added in v3.1.17

func NewNSQConsumerBuilder(topic, channel string) *NSQConsumerBuilder

NewNSQConsumerBuilder 创建消费者构建器

func (*NSQConsumerBuilder) Build added in v3.1.17

func (b *NSQConsumerBuilder) Build() (*NSQConsumer, error)

Build 构建 Consumer

func (*NSQConsumerBuilder) BuildAndStart added in v3.1.17

func (b *NSQConsumerBuilder) BuildAndStart(handler NSQHandlerFunc) (*NSQConsumer, error)

BuildAndStart 构建并启动消费者

func (*NSQConsumerBuilder) WithConcurrency added in v3.1.17

func (b *NSQConsumerBuilder) WithConcurrency(n int) *NSQConsumerBuilder

WithConcurrency 设置并发数

func (*NSQConsumerBuilder) WithLookupd added in v3.1.17

func (b *NSQConsumerBuilder) WithLookupd(addrs ...string) *NSQConsumerBuilder

WithLookupd 设置 lookupd 地址

func (*NSQConsumerBuilder) WithMaxAttempts added in v3.1.17

func (b *NSQConsumerBuilder) WithMaxAttempts(n uint16) *NSQConsumerBuilder

WithMaxAttempts 设置最大重试次数

func (*NSQConsumerBuilder) WithMaxBackoff added in v3.1.17

func (b *NSQConsumerBuilder) WithMaxBackoff(d time.Duration) *NSQConsumerBuilder

WithMaxBackoff 设置最大退避时间

func (*NSQConsumerBuilder) WithMaxInFlight added in v3.1.17

func (b *NSQConsumerBuilder) WithMaxInFlight(n int) *NSQConsumerBuilder

WithMaxInFlight 设置最大在途消息数

func (*NSQConsumerBuilder) WithMsgTimeout added in v3.1.17

func (b *NSQConsumerBuilder) WithMsgTimeout(d time.Duration) *NSQConsumerBuilder

WithMsgTimeout 设置消息处理超时

func (*NSQConsumerBuilder) WithNSQD added in v3.1.17

func (b *NSQConsumerBuilder) WithNSQD(addrs ...string) *NSQConsumerBuilder

WithNSQD 设置 nsqd 直连地址

type NSQConsumerConfig added in v3.1.17

type NSQConsumerConfig struct {
	Topic       string        // Topic 名称(必填)
	Channel     string        // Channel 名称(必填)
	NSQDs       []string      // 直连 nsqd 地址列表(如 ["127.0.0.1:4150"])
	Lookupds    []string      // nsqlookupd 地址列表(如 ["127.0.0.1:4161"])
	Concurrency int           // 并发处理数(默认 1)
	MaxInFlight int           // 最大在途消息数(默认 200)
	MaxAttempts uint16        // 最大重试次数(默认 5)
	MaxBackoff  time.Duration // 最大退避时间(默认 2m)
	MsgTimeout  time.Duration // 消息处理超时(0 使用服务端默认)
}

NSQConsumerConfig 消费者配置

type NSQHandlerContext added in v3.1.17

type NSQHandlerContext struct {
	context.Context
	Message *nsq.Message
	Cancel  context.CancelFunc
}

NSQHandlerContext 带超时的消息处理上下文

func NewNSQHandlerContext added in v3.1.17

func NewNSQHandlerContext(msg *nsq.Message, timeout time.Duration) *NSQHandlerContext

NewNSQHandlerContext 创建带超时的消息处理上下文

type NSQHandlerFunc added in v3.1.17

type NSQHandlerFunc func(msg *nsq.Message) error

NSQHandlerFunc 消息处理函数 返回 nil → FIN(确认处理完成) 返回 error → REQ(重新入队,自动退避重试)

type NSQProducer added in v3.1.17

type NSQProducer struct {
	*nsq.Producer
	// contains filtered or unexported fields
}

NSQProducer 封装 nsq.Producer

func NProducer added in v3.1.17

func NProducer() *NSQProducer

NProducer 获取全局 NSQ Producer

func NewNSQProducer added in v3.1.17

func NewNSQProducer(addr string, cfg *nsq.Config) (*NSQProducer, error)

NewNSQProducer 创建 Producer

func (*NSQProducer) DeferredPublish added in v3.1.17

func (p *NSQProducer) DeferredPublish(topic string, delay time.Duration, body []byte) error

DeferredPublish 延迟发布消息

func (*NSQProducer) DeferredPublishJSON added in v3.1.17

func (p *NSQProducer) DeferredPublishJSON(topic string, delay time.Duration, v any) error

DeferredPublishJSON 延迟发布 JSON 消息

func (*NSQProducer) MultiPublish added in v3.1.17

func (p *NSQProducer) MultiPublish(topic string, bodies [][]byte) error

MultiPublish 批量发布消息到同一 topic

func (*NSQProducer) Ping added in v3.1.17

func (p *NSQProducer) Ping() error

Ping 检测连接

func (*NSQProducer) Publish added in v3.1.17

func (p *NSQProducer) Publish(topic string, body []byte) error

Publish 发布消息

func (*NSQProducer) PublishJSON added in v3.1.17

func (p *NSQProducer) PublishJSON(topic string, v any) error

PublishJSON 发布 JSON 消息(自动序列化)

func (*NSQProducer) PublishString added in v3.1.17

func (p *NSQProducer) PublishString(topic, message string) error

PublishString 发布字符串消息

func (*NSQProducer) Stop added in v3.1.17

func (p *NSQProducer) Stop()

Stop 停止 Producer

type NextPage added in v3.1.8

type NextPage[T any] struct {
	P     int  `json:"p"`
	L     int  `json:"l"`
	Next  bool `json:"next"`
	Prev  bool `json:"prev"`
	Data  []T  `json:"data"`
	Extra any  `json:"extra,omitempty"`
}

func FindNextBy added in v3.1.8

func FindNextBy[T any](whr *Map, out *[]T, db ...*DB) (result NextPage[T], err error)

type NextPages

type NextPages struct {
	P     int  `json:"p"`
	L     int  `json:"l"`
	Next  bool `json:"next"`
	Prev  bool `json:"prev"`
	Data  any  `json:"data"`
	Extra any  `json:"extra,omitempty"`
}

func FindNext

func FindNext(whr *Map, out any, db ...*DB) (result NextPages, err error)

type Options

type Options map[string]any
var (
	Conf Options
)

func LoadConfigFile

func LoadConfigFile(file string, opts ...Options) Options

func (Options) As added in v3.1.8

func (d Options) As(k string, v any) error

func (*Options) GetAs

func (opt *Options) GetAs(k string, v any) error

func (*Options) GetBool

func (opt *Options) GetBool(k string, def ...bool) bool

func (*Options) GetInt

func (opt *Options) GetInt(k string, def ...int) int

func (*Options) GetInt64

func (opt *Options) GetInt64(k string, def ...int64) int64

func (*Options) GetMap

func (opt *Options) GetMap(k string, def ...Options) Options

func (*Options) GetPathBool added in v3.1.8

func (opt *Options) GetPathBool(path string, def ...bool) bool

GetPathBool 获取布尔值

func (*Options) GetPathInt added in v3.1.8

func (opt *Options) GetPathInt(path string, def ...int) int

同样添加其他类型的路径访问方法

func (*Options) GetPathString added in v3.1.8

func (opt *Options) GetPathString(path string, def ...string) string

GetPathString 支持通过点号路径获取嵌套配置 例如: GetPathString("telegram.token") 会获取 cfg["telegram"].(Options)["token"]

func (*Options) GetPathStrings added in v3.1.10

func (opt *Options) GetPathStrings(path string, def ...[]string) []string

GetPathStrings 获取字符串数组类型的配置值

func (*Options) GetString

func (opt *Options) GetString(k string, def ...string) string

func (*Options) GetStrings

func (opt *Options) GetStrings(k string, def ...[]string) []string

func (*Options) ToString

func (opt *Options) ToString(k string, def ...string) string

func (*Options) Value

func (opt *Options) Value(k string) (any, bool)

type Page added in v3.1.8

type Page[T any] struct {
	P     int   `json:"p"`
	L     int   `json:"l"`
	Total int64 `json:"total"`
	Data  []T   `json:"data"`
	Extra any   `json:"extra,omitempty"`
}

func FindPageBy added in v3.1.8

func FindPageBy[T any](whr *Map, out *[]T, db ...*DB) (result Page[T], err error)

FindPage Gorm find to page process whr

type Pages

type Pages struct {
	P     int   `json:"p"`
	L     int   `json:"l"`
	Total int64 `json:"total"`
	Data  any   `json:"data"`
	Extra any   `json:"extra,omitempty"`
}

func FindPage

func FindPage(whr *Map, out any, db ...*DB) (result Pages, err error)

FindPage Gorm find to page process whr

type RecoveryFunc

type RecoveryFunc func(c Ctx, err any)

RecoveryFunc defines the function passable to CustomRecovery.

type RedisClient added in v3.1.17

type RedisClient struct {
	*redis.Client
}

func RConn added in v3.1.17

func RConn(name ...string) *RedisClient

RConn 获取 Redis 连接(默认实例)

func (*RedisClient) BitCount added in v3.1.17

func (r *RedisClient) BitCount(ctx context.Context, key string, bitCount *redis.BitCount) (int64, error)

BitCount 统计位为1的数量

func (*RedisClient) Close added in v3.1.17

func (r *RedisClient) Close() error

Close 关闭连接

func (*RedisClient) Decr added in v3.1.17

func (r *RedisClient) Decr(ctx context.Context, key string) (int64, error)

Decr 原子递减

func (*RedisClient) Delete added in v3.1.17

func (r *RedisClient) Delete(ctx context.Context, keys ...string) error

Delete 删除

func (*RedisClient) Eval added in v3.1.17

func (r *RedisClient) Eval(ctx context.Context, script string, keys []string, args ...any) (any, error)

Eval 执行 Lua 脚本

func (*RedisClient) EvalSha added in v3.1.17

func (r *RedisClient) EvalSha(ctx context.Context, sha1 string, keys []string, args ...any) (any, error)

EvalSha 执行 Lua 脚本(通过 SHA1)

func (*RedisClient) Exists added in v3.1.17

func (r *RedisClient) Exists(ctx context.Context, key string) (bool, error)

Exists 是否存在

func (*RedisClient) Expire added in v3.1.17

func (r *RedisClient) Expire(ctx context.Context, key string, ttl time.Duration) error

Expire 设置过期时间

func (*RedisClient) Get added in v3.1.17

func (r *RedisClient) Get(ctx context.Context, key string) (string, error)

Get 获取值(redis.Nil 返回空字符串不报错)

func (*RedisClient) GetBit added in v3.1.17

func (r *RedisClient) GetBit(ctx context.Context, key string, offset int64) (int64, error)

GetBit 获取位

func (*RedisClient) GetInt added in v3.1.17

func (r *RedisClient) GetInt(ctx context.Context, key string) (int, error)

GetInt 获取整数值

func (*RedisClient) GetJSON added in v3.1.17

func (r *RedisClient) GetJSON(ctx context.Context, key string, v any) error

GetJSON 自动反序列化读取

func (*RedisClient) HDel added in v3.1.17

func (r *RedisClient) HDel(ctx context.Context, key string, fields ...string) error

HDel 删除 Hash 字段

func (*RedisClient) HExists added in v3.1.17

func (r *RedisClient) HExists(ctx context.Context, key, field string) (bool, error)

HExists 判断 Hash 字段是否存在

func (*RedisClient) HGet added in v3.1.17

func (r *RedisClient) HGet(ctx context.Context, key, field string) (string, error)

HGet 获取 Hash 字段值

func (*RedisClient) HGetAll added in v3.1.17

func (r *RedisClient) HGetAll(ctx context.Context, key string) (map[string]string, error)

HGetAll 获取 Hash 所有字段

func (*RedisClient) HGetJSON added in v3.1.17

func (r *RedisClient) HGetJSON(ctx context.Context, key, field string, v any) error

HGetJSON Hash 字段 JSON 反序列化读取

func (*RedisClient) HIncrBy added in v3.1.17

func (r *RedisClient) HIncrBy(ctx context.Context, key, field string, incr int64) (int64, error)

HIncrBy Hash 字段原子递增

func (*RedisClient) HLen added in v3.1.17

func (r *RedisClient) HLen(ctx context.Context, key string) (int64, error)

HLen Hash 字段数量

func (*RedisClient) HSet added in v3.1.17

func (r *RedisClient) HSet(ctx context.Context, key string, values ...any) error

HSet 设置 Hash 字段

func (*RedisClient) HSetJSON added in v3.1.17

func (r *RedisClient) HSetJSON(ctx context.Context, key, field string, value any) error

HSetJSON Hash 字段 JSON 序列化存储

func (*RedisClient) Incr added in v3.1.17

func (r *RedisClient) Incr(ctx context.Context, key string) (int64, error)

Incr 原子递增

func (*RedisClient) IncrBy added in v3.1.17

func (r *RedisClient) IncrBy(ctx context.Context, key string, value int64) (int64, error)

IncrBy 原子增减指定值

func (*RedisClient) IncrWithTTL added in v3.1.17

func (r *RedisClient) IncrWithTTL(ctx context.Context, key string, ttl time.Duration) (int64, error)

IncrWithTTL 递增并设置过期(常用于限流)

func (*RedisClient) LLen added in v3.1.17

func (r *RedisClient) LLen(ctx context.Context, key string) (int64, error)

LLen 列表长度

func (*RedisClient) LPop added in v3.1.17

func (r *RedisClient) LPop(ctx context.Context, key string) (string, error)

LPop 左侧出队

func (*RedisClient) LPush added in v3.1.17

func (r *RedisClient) LPush(ctx context.Context, key string, values ...any) error

LPush 左侧入队

func (*RedisClient) LRange added in v3.1.17

func (r *RedisClient) LRange(ctx context.Context, key string, start, stop int64) ([]string, error)

LRange 获取列表范围

func (*RedisClient) NewStreamConsumer added in v3.1.17

func (r *RedisClient) NewStreamConsumer(conf StreamConsumerConfig) *StreamConsumer

NewStreamConsumer 创建 Stream 消费者

func (*RedisClient) Ping added in v3.1.17

func (r *RedisClient) Ping(ctx context.Context) error

Ping 检测连接

func (*RedisClient) Pipeline added in v3.1.17

func (r *RedisClient) Pipeline() redis.Pipeliner

Pipeline 获取管道

func (*RedisClient) Pipelined added in v3.1.17

func (r *RedisClient) Pipelined(ctx context.Context, fn func(redis.Pipeliner) error) ([]redis.Cmder, error)

Pipelined 执行管道操作

func (*RedisClient) Publish added in v3.1.17

func (r *RedisClient) Publish(ctx context.Context, channel string, message any) error

Publish 发布消息

func (*RedisClient) RPop added in v3.1.17

func (r *RedisClient) RPop(ctx context.Context, key string) (string, error)

RPop 右侧出队

func (*RedisClient) RPush added in v3.1.17

func (r *RedisClient) RPush(ctx context.Context, key string, values ...any) error

RPush 右侧入队

func (*RedisClient) SAdd added in v3.1.17

func (r *RedisClient) SAdd(ctx context.Context, key string, members ...any) error

SAdd 添加成员到集合

func (*RedisClient) SCard added in v3.1.17

func (r *RedisClient) SCard(ctx context.Context, key string) (int64, error)

SCard 集合成员数量

func (*RedisClient) SIsMember added in v3.1.17

func (r *RedisClient) SIsMember(ctx context.Context, key string, member any) (bool, error)

SIsMember 判断是否为集合成员

func (*RedisClient) SMembers added in v3.1.17

func (r *RedisClient) SMembers(ctx context.Context, key string) ([]string, error)

SMembers 获取集合所有成员

func (*RedisClient) SRem added in v3.1.17

func (r *RedisClient) SRem(ctx context.Context, key string, members ...any) error

SRem 从集合移除成员

func (*RedisClient) Scan added in v3.1.17

func (r *RedisClient) Scan(ctx context.Context, cursor uint64, match string, count int64) *redis.ScanCmd

Scan 扫描匹配的 key

func (*RedisClient) ScriptLoad added in v3.1.17

func (r *RedisClient) ScriptLoad(ctx context.Context, script string) (string, error)

ScriptLoad 预加载 Lua 脚本

func (*RedisClient) Set added in v3.1.17

func (r *RedisClient) Set(ctx context.Context, key string, value any, ttl ...time.Duration) error

Set 设置值(可选TTL)

func (*RedisClient) SetBit added in v3.1.17

func (r *RedisClient) SetBit(ctx context.Context, key string, offset int64, value int) error

SetBit 设置位

func (*RedisClient) SetJSON added in v3.1.17

func (r *RedisClient) SetJSON(ctx context.Context, key string, value any, ttl ...time.Duration) error

SetJSON 自动序列化存储

func (*RedisClient) Subscribe added in v3.1.17

func (r *RedisClient) Subscribe(ctx context.Context, channel string, handler func(string)) error

Subscribe 订阅频道(阻塞式)

func (*RedisClient) TTL added in v3.1.17

func (r *RedisClient) TTL(ctx context.Context, key string) (time.Duration, error)

TTL 获取剩余过期时间

func (*RedisClient) TxPipeline added in v3.1.17

func (r *RedisClient) TxPipeline() redis.Pipeliner

TxPipeline 获取事务管道

func (*RedisClient) XAck added in v3.1.17

func (r *RedisClient) XAck(ctx context.Context, stream, group string, ids ...string) error

XAck 确认消息已处理

func (*RedisClient) XAdd added in v3.1.17

func (r *RedisClient) XAdd(ctx context.Context, stream string, fields map[string]any, id ...string) (string, error)

XAdd 向 Stream 添加消息 返回消息 ID

func (*RedisClient) XAddJSON added in v3.1.17

func (r *RedisClient) XAddJSON(ctx context.Context, stream string, value any, id ...string) (string, error)

XAddJSON 向 Stream 添加 JSON 消息 将 value 序列化为 JSON 存入 _data 字段

func (*RedisClient) XClaim added in v3.1.17

func (r *RedisClient) XClaim(ctx context.Context, stream, group, consumer string, minIdleTime time.Duration, ids ...string) ([]StreamMessage, error)

XClaim 认领待处理消息(用于故障恢复)

func (*RedisClient) XDel added in v3.1.17

func (r *RedisClient) XDel(ctx context.Context, stream string, ids ...string) (int64, error)

XDel 删除 Stream 中的消息

func (*RedisClient) XGroupCreate added in v3.1.17

func (r *RedisClient) XGroupCreate(ctx context.Context, stream, group, startID string) error

XGroupCreate 创建消费者组 startID: "0" 从头消费, "$" 只消费新消息

func (*RedisClient) XGroupDestroy added in v3.1.17

func (r *RedisClient) XGroupDestroy(ctx context.Context, stream, group string) error

XGroupDestroy 删除消费者组

func (*RedisClient) XLen added in v3.1.17

func (r *RedisClient) XLen(ctx context.Context, stream string) (int64, error)

XLen 获取 Stream 长度

func (*RedisClient) XPending added in v3.1.17

func (r *RedisClient) XPending(ctx context.Context, stream, group string) (*redis.XPending, error)

XPending 获取消费者组的待处理消息信息

func (*RedisClient) XRange added in v3.1.17

func (r *RedisClient) XRange(ctx context.Context, stream, start, stop string, count ...int64) ([]StreamMessage, error)

XRange 按 ID 范围读取消息

func (*RedisClient) XRead added in v3.1.17

func (r *RedisClient) XRead(ctx context.Context, stream string, startID string, count ...int64) ([]StreamMessage, error)

XRead 从 Stream 读取消息(非消费者组模式)

func (*RedisClient) XReadGroup added in v3.1.17

func (r *RedisClient) XReadGroup(ctx context.Context, stream, group, consumer string, count int64, block time.Duration) ([]StreamMessage, error)

XReadGroup 从消费者组读取消息

func (*RedisClient) XTrim added in v3.1.17

func (r *RedisClient) XTrim(ctx context.Context, stream string, maxLen int64) error

XTrim 按 maxlen 裁剪 Stream

func (*RedisClient) ZAdd added in v3.1.17

func (r *RedisClient) ZAdd(ctx context.Context, key string, members ...redis.Z) error

ZAdd 添加成员到有序集合

func (*RedisClient) ZCard added in v3.1.17

func (r *RedisClient) ZCard(ctx context.Context, key string) (int64, error)

ZCard 有序集合成员数量

func (*RedisClient) ZIncrBy added in v3.1.17

func (r *RedisClient) ZIncrBy(ctx context.Context, key string, increment float64, member string) (float64, error)

ZIncrBy 有序集合成员分数递增

func (*RedisClient) ZRangeByScore added in v3.1.17

func (r *RedisClient) ZRangeByScore(ctx context.Context, key string, opt *redis.ZRangeBy) ([]string, error)

ZRangeByScore 按分数范围获取有序集合成员

func (*RedisClient) ZRem added in v3.1.17

func (r *RedisClient) ZRem(ctx context.Context, key string, members ...any) error

ZRem 移除有序集合成员

func (*RedisClient) ZRevRangeByScore added in v3.1.17

func (r *RedisClient) ZRevRangeByScore(ctx context.Context, key string, opt *redis.ZRangeBy) ([]string, error)

ZRevRangeByScore 按分数范围倒序获取有序集合成员

func (*RedisClient) ZScore added in v3.1.17

func (r *RedisClient) ZScore(ctx context.Context, key string, member string) (float64, error)

ZScore 获取有序集合成员分数

type ResponseWriter

type ResponseWriter interface {
	http.ResponseWriter
	http.Hijacker
	http.Flusher

	// Returns the HTTP response status code of the current request.
	Status() int

	// Returns the number of bytes already written into the response http body.
	// See Written()
	Size() int

	// Writes the string into the response body.
	WriteString(string) (int, error)

	// Returns true if the response body was already written.
	Written() bool

	// Forces to write the http header (status code + headers).
	DoWriteHeader()

	// get the http.Pusher for server push
	Pusher() http.Pusher
}

ResponseWriter ...

type RestfulDefine

type RestfulDefine struct {
	Data    string
	Status  string
	Message string
	Code    any
}

type RotatingLogWriter added in v3.1.19

type RotatingLogWriter struct {
	// contains filtered or unexported fields
}

func NewRotatingLogWriter added in v3.1.19

func NewRotatingLogWriter(path string, opts ...string) (*RotatingLogWriter, error)

func NewRotatingLogWriterConfig added in v3.1.19

func NewRotatingLogWriterConfig(path string, cfg LogRotateConfig) (*RotatingLogWriter, error)

func (*RotatingLogWriter) Close added in v3.1.19

func (w *RotatingLogWriter) Close() error

func (*RotatingLogWriter) RedirectStdout added in v3.1.19

func (w *RotatingLogWriter) RedirectStdout() error

func (*RotatingLogWriter) Write added in v3.1.19

func (w *RotatingLogWriter) Write(p []byte) (int, error)

type RouteNode

type RouteNode struct {
	// contains filtered or unexported fields
}

type Router

type Router interface {
	Use(args ...any) Router

	GET(path string, handler any, middleware ...any) Router
	HEAD(path string, handler any, middleware ...any) Router
	POST(path string, handler any, middleware ...any) Router
	PUT(path string, handler any, middleware ...any) Router
	DELETE(path string, handler any, middleware ...any) Router
	CONNECT(path string, handler any, middleware ...any) Router
	OPTIONS(path string, handler any, middleware ...any) Router
	TRACE(path string, handler any, middleware ...any) Router
	PATCH(path string, handler any, middleware ...any) Router
	ALL(path string, handler any, middleware ...any) Router
	Group(prefix string, handlers ...HandlerFuncs) Router
	// contains filtered or unexported methods
}

Router defines all router handle interface, including app and group router.

type SModels added in v3.0.3

type SModels struct {
	ID        sid.ID          `json:"id,omitzero" gorm:"primaryKey;autoIncrement:false;comment:主键"`
	CreatedAt *time.Time      `json:"created_at,omitempty" gorm:"<-:create;comment:创建时间"`
	UpdatedAt *time.Time      `json:"updated_at,omitempty" gorm:"autoUpdateTime;comment:更新时间"`
	DeletedAt *gorm.DeletedAt `json:"deleted_at,omitempty" gorm:"index;comment:删除时间"`
}

func (*SModels) BeforeCreate added in v3.0.3

func (m *SModels) BeforeCreate(tx *DB) error

type StreamConsumer added in v3.1.17

type StreamConsumer struct {
	// contains filtered or unexported fields
}

func (*StreamConsumer) Run added in v3.1.17

func (c *StreamConsumer) Run(ctx context.Context, handler func(ctx context.Context, msg StreamMessage) error) error

Run 启动消费者(阻塞运行,直到 context 取消) handler 返回 nil 自动 ACK,返回 error 不 ACK(进入 pending 列表等待重试)

type StreamConsumerConfig added in v3.1.17

type StreamConsumerConfig struct {
	Stream     string        // Stream 名称
	Group      string        // 消费者组名称
	Consumer   string        // 消费者名称
	Count      int64         // 每次读取条数(默认 10)
	Block      time.Duration // 阻塞等待时间(默认 5s)
	ClaimIdle  time.Duration // 认领待处理消息的最小空闲时间(默认 30s,0 禁用)
	ClaimCount int64         // 每次认领的最大条数(默认 10)
	AutoAck    bool          // 处理成功是否自动 ACK(默认 true)
}

type StreamMessage added in v3.1.17

type StreamMessage struct {
	ID     string         // 消息 ID (如 "1672531200000-0")
	Fields map[string]any // 消息字段
}

StreamMessage 表示一条 Stream 消息

type StringOrNil

type StringOrNil string

空字符串 存入数据库 存 NULL ,这样会跳过数据库唯一索引的检查

func (*StringOrNil) Scan

func (s *StringOrNil) Scan(src any) error

implements sql.Scanner, will be invoked automatically when read from the db

func (StringOrNil) String

func (s StringOrNil) String() string

func (StringOrNil) Value

func (s StringOrNil) Value() (driver.Value, error)

implements driver.Valuer, will be invoked automatically when written to the db

type TypeConstraint

type TypeConstraint int16

TypeConstraint parameter constraint types

type UUID

type UUID struct {
	uuid.UUID
}

func ExtractUUIDs

func ExtractUUIDs[T HasUUID](items []T) []UUID

func MustUUID

func MustUUID(s string) UUID

func NewUUID

func NewUUID() UUID

func ParseBytes

func ParseBytes(b []byte) (UUID, error)

ParseBytes is like Parse, except it parses a byte slice instead of a string.

func SafeToUUIDs

func SafeToUUIDs(items any) []UUID

SafeToUUIDs 安全地将任意类型转换为 []UUID

func ToUUIDsFromAny

func ToUUIDsFromAny(items []any) []UUID

ToUUIDsFromAny 把 []any 转换成 []UUID

func UUIDFromString

func UUIDFromString(s string) (UUID, error)

func (UUID) Bytes

func (u UUID) Bytes() []byte

func (UUID) GormDBDataType

func (UUID) GormDBDataType(db *gorm.DB, field *schema.Field) string

func (UUID) GormDataType

func (uuid UUID) GormDataType() string

GormDataType gorm common data type

func (UUID) IsEmpty

func (u UUID) IsEmpty() bool

func (UUID) MarshalBinary

func (u UUID) MarshalBinary() (data []byte, err error)

func (UUID) MarshalText

func (id UUID) MarshalText() ([]byte, error)

MarshalText implements encoding.TextMarshaler.

func (*UUID) Scan

func (uuid *UUID) Scan(src any) error

Scan implements sql.Scanner so UUIDs can be read from databases transparently. Currently, database types that map to string and []byte are supported. Please consult database-specific driver documentation for matching types.

func (UUID) String

func (u UUID) String() string

func (*UUID) UnmarshalBinary

func (u *UUID) UnmarshalBinary(data []byte) error

func (*UUID) UnmarshalText

func (uuid *UUID) UnmarshalText(data []byte) error

UnmarshalText implements encoding.TextUnmarshaler.

func (UUID) Value

func (uuid UUID) Value() (driver.Value, error)

Value implements sql.Valuer so that UUIDs can be written to databases transparently. Currently, UUIDs map to strings. Please consult database-specific driver documentation for matching types.

type Writers

type Writers struct{}

func (Writers) Printf

func (Writers) Printf(f string, args ...any)

Directories

Path Synopsis
cmd
corectl command
coregen command
* KV 存储相关方法 提供对etcd KV存储的封装,包括Put、Get等操作
* KV 存储相关方法 提供对etcd KV存储的封装,包括Put、Get等操作
example
restful command
websocket command
work command
middleware
Package reuseport provides TCP net.Listener with SO_REUSEPORT support.
Package reuseport provides TCP net.Listener with SO_REUSEPORT support.
Package tcplisten provides customizable TCP net.Listener with various performance-related options:
Package tcplisten provides customizable TCP net.Listener with various performance-related options:

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL