最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Go項(xiàng)目中使用Casbin實(shí)現(xiàn)RBAC權(quán)限管理教程

 更新時間:2026年01月29日 08:26:55   作者:皖南大花豬  
本文主要介紹了Go項(xiàng)目中使用Casbin實(shí)現(xiàn)RBAC權(quán)限管理教程,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

?? 前言

在構(gòu)建企業(yè)級 Go 管理后臺系統(tǒng)時,權(quán)限管理是一個核心功能。Casbin 是一個強(qiáng)大的、開源的訪問控制庫,支持多種訪問控制模型(ACL、RBAC、ABAC 等)。本文將詳細(xì)介紹如何在 Go 項(xiàng)目中使用 Casbin 實(shí)現(xiàn)完整的 RBAC(基于角色的訪問控制)權(quán)限管理系統(tǒng)。

本文基于開源項(xiàng)目 gin-layout 的實(shí)際實(shí)現(xiàn),這是一個功能完整的 Go Admin 后臺管理系統(tǒng)框架,提供了開箱即用的權(quán)限管理解決方案。

?? 什么是 Casbin?

Casbin 是一個強(qiáng)大的、開源的訪問控制庫,支持多種訪問控制模型:

  • ACL (Access Control List) - 訪問控制列表
  • RBAC (Role-Based Access Control) - 基于角色的訪問控制
  • ABAC (Attribute-Based Access Control) - 基于屬性的訪問控制
  • RESTful - RESTful 風(fēng)格的訪問控制

Casbin 的核心思想是將訪問控制模型與策略分離,通過配置文件定義訪問控制模型,通過適配器(Adapter)存儲策略規(guī)則。

?? 項(xiàng)目依賴

首先,我們需要安裝 Casbin 相關(guān)的依賴包:

go get github.com/casbin/casbin/v2
go get github.com/casbin/gorm-adapter/v3

?? 1. Casbin 模型配置

Casbin 使用模型文件(Model)來定義訪問控制規(guī)則。在項(xiàng)目中,我們創(chuàng)建了 rbac_model.conf 文件:

[request_definition]
r = sub, obj, act

[policy_definition]
p = sub, obj, act

[role_definition]
g = _, _

[policy_effect]
e = some(where (p.eft == allow))

[matchers]
m = (g(r.sub, p.sub) && keyMatch3(r.obj, p.obj) && regexMatch(r.act, p.act))

配置說明

  • request_definition: 定義請求格式,r = sub, obj, act 表示請求包含主體(subject)、對象(object)和操作(action)
  • policy_definition: 定義策略格式,p = sub, obj, act 表示策略包含主體、對象和操作
  • role_definition: 定義角色繼承關(guān)系,g = _, _ 表示角色繼承關(guān)系(如 g, user:1, role:1 表示用戶1繼承角色1)
  • policy_effect: 定義策略效果,e = some(where (p.eft == allow)) 表示只要有一個策略允許就允許訪問
  • matchers: 定義匹配規(guī)則
    • g(r.sub, p.sub): 檢查請求主體是否繼承策略主體(角色繼承)
    • keyMatch3(r.obj, p.obj): 使用 keyMatch3 函數(shù)匹配路徑(支持 * 通配符)
    • regexMatch(r.act, p.act): 使用正則表達(dá)式匹配 HTTP 方法

?? 2. Casbin 初始化

在項(xiàng)目中,我們封裝了一個 Casbin 工具包 internal/pkg/utils/casbin/casbin.go

package casbinx

import (
    "github.com/casbin/casbin/v2"
    "github.com/casbin/casbin/v2/model"
    gormadapter "github.com/casbin/gorm-adapter/v3"
    "gorm.io/gorm"
)

type CasbinEnforcer struct {
    *casbin.Enforcer
    errInit error
    tx      *gorm.DB
    model   model.Model
}

var casbinx = &CasbinEnforcer{}

// InitEnforcer 初始化 Casbin Enforcer(僅執(zhí)行一次)
func InitEnforcer() error {
    once.Do(func() {
        // 1. 加載模型文件
        modelPath, err := getModelPath()
        if err != nil {
            casbinx.errInit = err
            return
        }

        m, err := model.NewModelFromFile(modelPath)
        if err != nil {
            casbinx.errInit = fmt.Errorf("加載模型失敗: %w", err)
            return
        }
        casbinx.model = m

        // 2. 創(chuàng)建 GORM 適配器
        db := data.MysqlDB()
        gormadapter.TurnOffAutoMigrate(db)
        adapter, err := gormadapter.NewAdapterByDB(db)
        if err != nil {
            casbinx.errInit = fmt.Errorf("創(chuàng)建適配器失敗: %w", err)
            return
        }

        // 3. 創(chuàng)建 Enforcer
        enforcer, err := casbin.NewEnforcer(m, adapter)
        if err != nil {
            casbinx.errInit = fmt.Errorf("創(chuàng)建 Enforcer 失敗: %w", err)
            return
        }

        // 4. 啟用自動保存
        enforcer.EnableAutoSave(true)

        casbinx.Enforcer = enforcer
    })
    return casbinx.errInit
}

// GetEnforcer 返回已初始化的 Enforcer 實(shí)例
func GetEnforcer() *CasbinEnforcer {
    if casbinx.Enforcer == nil {
        if err := InitEnforcer(); err != nil {
            return nil
        }
    }
    return casbinx
}

關(guān)鍵點(diǎn)說明

  1. 單例模式: 使用 sync.Once 確保 Enforcer 只初始化一次
  2. GORM 適配器: 使用 gorm-adapter 將策略存儲在 MySQL 數(shù)據(jù)庫中
  3. 自動保存: EnableAutoSave(true) 確保策略變更后自動保存到數(shù)據(jù)庫
  4. 模型加載: 從配置文件加載訪問控制模型

?? 3. 權(quán)限檢查中間件

在 Gin 框架中,我們通過中間件來實(shí)現(xiàn)權(quán)限檢查:

// internal/middleware/admin_auth.go

func AdminAuthHandler() gin.HandlerFunc {
    return func(c *gin.Context) {
        // 1. 獲取用戶信息
        uid := c.GetUint("uid")
        if uid == 0 {
            response.Fail(c, e.NotLogin, "請先登錄")
            c.Abort()
            return
        }

        adminUser := getUserFromContext(c)
        if adminUser == nil {
            response.Fail(c, e.NotLogin, "登錄已失效,請重新登錄")
            c.Abort()
            return
        }

        // 2. 超級管理員跳過權(quán)限檢查
        if !isSuperAdmin(adminUser) {
            // 3. 檢查接口權(quán)限
            if err := checkPermission(c, adminUser); err != nil {
                if businessErr, ok := err.(*e.BusinessError); ok {
                    response.Fail(c, businessErr.GetCode(), businessErr.GetMessage())
                } else {
                    response.Fail(c, e.ServerErr, "權(quán)限驗(yàn)證失敗")
                }
                c.Abort()
                return
            }
        }

        c.Next()
    }
}

// checkPermission 檢查接口權(quán)限
func checkPermission(c *gin.Context, adminUser *model.AdminUser) error {
    enforcer := casbinx.GetEnforcer()
    if enforcer.Error() != nil {
        log.Logger.Error("權(quán)限驗(yàn)證初始化失敗", zap.Error(enforcer.Error()))
        return e.NewBusinessError(e.ServerErr, "權(quán)限驗(yàn)證初始化失敗")
    }

    // 構(gòu)建權(quán)限檢查的 key
    userKey := fmt.Sprintf("%s%s%d", global.CasbinAdminUserPrefix, global.CasbinSeparator, adminUser.ID)
    path := c.Request.URL.Path
    method := c.Request.Method

    // 檢查權(quán)限
    ok, err := enforcer.Enforce(userKey, path, method)
    if err != nil {
        log.Logger.Error("權(quán)限驗(yàn)證失敗", zap.Error(err))
        return e.NewBusinessError(e.ServerErr, "權(quán)限驗(yàn)證失敗")
    }

    // 如果沒有權(quán)限,檢查接口是否需要授權(quán)
    if !ok {
        if model.NewApi().CheckoutRouteIsAuth(path, method) {
            return e.NewBusinessError(e.AuthorizationErr, "暫無接口操作權(quán)限")
        }
    }

    return nil
}

權(quán)限檢查流程

  1. 獲取用戶信息: 從 JWT Token 中解析用戶 ID
  2. 構(gòu)建用戶標(biāo)識: 使用 adminUser:1 格式標(biāo)識用戶(1 為用戶 ID)
  3. 調(diào)用 Enforce: 使用 enforcer.Enforce(userKey, path, method) 檢查權(quán)限
  4. 處理結(jié)果: 如果沒有權(quán)限且接口需要授權(quán),返回權(quán)限不足錯誤

?? 4. 策略管理

4.1 策略存儲格式

在數(shù)據(jù)庫中,策略存儲在 casbin_rule 表中,表結(jié)構(gòu)如下:

CREATE TABLE `casbin_rule` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT,
  `ptype` varchar(100) DEFAULT NULL COMMENT '策略類型:p(策略) 或 g(角色繼承)',
  `v0` varchar(100) DEFAULT NULL COMMENT '主體(subject)',
  `v1` varchar(100) DEFAULT NULL COMMENT '對象(object)',
  `v2` varchar(100) DEFAULT NULL COMMENT '操作(action)',
  `v3` varchar(100) DEFAULT NULL,
  `v4` varchar(100) DEFAULT NULL,
  `v5` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_casbin_rule` (`ptype`, `v0`, `v1`, `v2`, `v3`, `v4`, `v5`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

4.2 策略類型

P 策略(權(quán)限策略)

格式:[p, subject, object, action]

示例:

  • [p, menu:1, /api/v1/user/list, GET] - 菜單1可以訪問 /api/v1/user/list 的 GET 方法
  • [p, role:1, /api/v1/user/*, *] - 角色1可以訪問所有 /api/v1/user/* 路徑的所有方法

G 策略(角色繼承)

格式:[g, user, role]

示例:

  • [g, adminUser:1, role:1] - 用戶1繼承角色1的所有權(quán)限
  • [g, role:1, menu:1] - 角色1繼承菜單1的所有權(quán)限
  • [g, dept:1, role:1] - 部門1繼承角色1的所有權(quán)限

4.3 編輯權(quán)限策略

項(xiàng)目中提供了 EditPolicyPermissions 方法來編輯權(quán)限策略:

// EditPolicyPermissions 編輯策略權(quán)限
// 策略格式:[p, 菜單ID, 接口路徑, 接口方法]
func (e *CasbinEnforcer) EditPolicyPermissions(user string, policy [][]string) error {
    return e.WithTransaction(func(enforcer casbin.IEnforcer) error {
        // 1. 刪除用戶的所有權(quán)限
        _, err := enforcer.DeletePermissionsForUser(user)
        if err != nil {
            return err
        }

        if len(policy) == 0 {
            return nil
        }

        // 2. 構(gòu)建完整的策略規(guī)則
        var policies [][]string
        for _, p := range policy {
            if len(p) > 0 {
                // 策略格式:[user, route, method]
                policies = append(policies, append([]string{user}, p...))
            }
        }

        // 3. 批量添加所有策略
        ok, err := enforcer.AddPolicies(policies)
        if err != nil {
            return err
        }

        if !ok {
            return errors.New("添加權(quán)限失敗")
        }

        return nil
    })
}

4.4 編輯角色繼承

項(xiàng)目中提供了 EditPolicyRoles 方法來編輯角色繼承關(guān)系:

// EditPolicyRoles 編輯策略角色
// 策略格式:[g, user, role]
func (e *CasbinEnforcer) EditPolicyRoles(user string, policy []string) error {
    return e.WithTransaction(func(enforcer casbin.IEnforcer) error {
        // 1. 刪除用戶的所有角色
        _, err := enforcer.DeleteRolesForUser(user)
        if err != nil {
            return err
        }

        if len(policy) == 0 {
            return nil
        }

        // 2. 構(gòu)建完整的角色繼承規(guī)則
        var rules [][]string
        for _, role := range policy {
            if role != "" {
                // 策略格式:[user, role]
                rules = append(rules, []string{user, role})
            }
        }

        // 3. 批量添加所有角色繼承關(guān)系
        ok, err := enforcer.AddGroupingPolicies(rules)
        if err != nil {
            return err
        }

        if !ok {
            return errors.New("添加權(quán)限失敗")
        }

        return nil
    })
}

??? 5. 實(shí)際應(yīng)用場景

5.1 菜單權(quán)限管理

在管理后臺系統(tǒng)中,菜單通常與 API 接口關(guān)聯(lián)。當(dāng)用戶編輯菜單權(quán)限時,需要更新 Casbin 策略:

// internal/service/permission/menu.go

// UpdateMenuPermissions 更新菜單權(quán)限
func (s *MenuService) UpdateMenuPermissions(menu *model.Menu, apiList []uint, tx ...*gorm.DB) error {
    // 1. 查詢 API 信息
    apis := model.List(model.NewApi(), "id IN ?", []any{apiList}, model.ListOptionalParams{
        SelectFields: []string{"id", "route", "method"},
    })

    // 2. 構(gòu)建策略規(guī)則
    policy := lo.Map(apis, func(api *model.Api, _ int) []string {
        return []string{api.Route, api.Method}
    })

    // 3. 更新 Casbin 策略
    menuName := fmt.Sprintf("%s%s%d", global.CasbinMenuPrefix, global.CasbinSeparator, menu.ID)
    enforcer := casbinx.GetEnforcer()
    if len(tx) > 0 {
        enforcer.SetDB(tx[0])
    }
    
    return enforcer.EditPolicyPermissions(menuName, policy)
}

5.2 用戶角色分配

當(dāng)為用戶分配角色時,需要更新角色繼承關(guān)系:

// internal/service/permission/admin_user.go

// EditUserRoles 編輯用戶角色
func (s *AdminUserService) EditUserRoles(uid uint, roleIds []uint, tx ...*gorm.DB) error {
    // 1. 構(gòu)建角色標(biāo)識列表
    roleList := lo.Map(roleIds, func(roleId uint, _ int) string {
        return fmt.Sprintf("%s%s%d", global.CasbinRolePrefix, global.CasbinSeparator, roleId)
    })

    // 2. 更新角色繼承關(guān)系
    userName := fmt.Sprintf("%s%s%d", global.CasbinAdminUserPrefix, global.CasbinSeparator, uid)
    enforcer := casbinx.GetEnforcer()
    if len(tx) > 0 {
        enforcer.SetDB(tx[0])
    }
    
    return enforcer.EditPolicyRoles(userName, roleList)
}

5.3 角色權(quán)限管理

角色可以繼承菜單的權(quán)限,也可以繼承其他角色的權(quán)限:

// internal/service/permission/role.go

// EditRoleMenus 編輯角色菜單
func (s *RoleService) EditRoleMenus(roleId uint, menuIds []uint, tx ...*gorm.DB) error {
    // 1. 構(gòu)建菜單標(biāo)識列表
    menuList := lo.Map(menuIds, func(menuId uint, _ int) string {
        return fmt.Sprintf("%s%s%d", global.CasbinMenuPrefix, global.CasbinSeparator, menuId)
    })

    // 2. 更新角色繼承關(guān)系
    roleName := fmt.Sprintf("%s%s%d", global.CasbinRolePrefix, global.CasbinSeparator, roleId)
    enforcer := casbinx.GetEnforcer()
    if len(tx) > 0 {
        enforcer.SetDB(tx[0])
    }
    
    return enforcer.EditPolicyRoles(roleName, menuList)
}

?? 6. 事務(wù)支持

在實(shí)際應(yīng)用中,權(quán)限更新通常需要與業(yè)務(wù)數(shù)據(jù)更新在同一個事務(wù)中。項(xiàng)目提供了事務(wù)支持:

// WithTransaction 執(zhí)行事務(wù)中的操作
func (e *CasbinEnforcer) WithTransaction(fc func(e casbin.IEnforcer) error) (err error) {
    a, ok := e.GetAdapter().(*gormadapter.Adapter)
    if !ok {
        return errors.New("適配器類型錯誤")
    }

    if e.tx != nil {
        if !isInTransaction(e.tx) {
            return errors.New("請先通過 GORM 開啟事務(wù)后傳入 SetDB")
        }

        defer func() {
            // 操作完成后,重置適配器
            e.SetAdapter(a.Copy())
            e.tx = nil
        }()

        // 創(chuàng)建事務(wù)適配器
        gormadapter.TurnOffAutoMigrate(e.tx)
        txAdapter, err := gormadapter.NewAdapterByDB(e.tx)
        if err != nil {
            return err
        }
        e.SetAdapter(txAdapter)
    }

    err = fc(e.Enforcer)
    return
}

使用示例:

// 在 GORM 事務(wù)中使用 Casbin
db.Transaction(func(tx *gorm.DB) error {
    // 1. 設(shè)置事務(wù)
    enforcer := casbinx.GetEnforcer().SetDB(tx)

    // 2. 更新業(yè)務(wù)數(shù)據(jù)
    // ... 業(yè)務(wù)邏輯 ...

    // 3. 更新權(quán)限策略(在事務(wù)中)
    menuName := fmt.Sprintf("menu:%d", menuId)
    return enforcer.EditPolicyPermissions(menuName, policy)
})

?? 7. 策略重新加載

當(dāng)策略更新后,需要重新加載策略到內(nèi)存中:

// 重新加載策略
enforcer := casbinx.GetEnforcer()
if err := enforcer.LoadPolicy(); err != nil {
    log.Logger.Error("重新加載策略失敗", zap.Error(err))
}

注意:雖然啟用了 EnableAutoSave(true),但這只保證策略保存到數(shù)據(jù)庫,不會自動加載到內(nèi)存。在策略更新后,需要手動調(diào)用 LoadPolicy() 重新加載。

?? 8. 權(quán)限標(biāo)識規(guī)范

項(xiàng)目中定義了統(tǒng)一的權(quán)限標(biāo)識前綴:

// internal/global/auth.go

const (
    CasbinAdminUserPrefix = "adminUser"  // 用戶前綴
    CasbinRolePrefix     = "role"        // 角色前綴
    CasbinMenuPrefix     = "menu"        // 菜單前綴
    CasbinDeptPrefix     = "dept"        // 部門前綴
    CasbinSeparator      = ":"           // 分隔符
)

權(quán)限標(biāo)識格式:

  • 用戶:adminUser:1(用戶 ID 為 1)
  • 角色:role:1(角色 ID 為 1)
  • 菜單:menu:1(菜單 ID 為 1)
  • 部門:dept:1(部門 ID 為 1)

?? 9. 常見問題與解決方案

9.1 權(quán)限更新后不生效

問題:更新策略后,權(quán)限檢查仍然使用舊策略。

解決方案:在策略更新后,調(diào)用 LoadPolicy() 重新加載策略:

enforcer := casbinx.GetEnforcer()
// 更新策略
enforcer.EditPolicyPermissions(userName, policy)
// 重新加載策略
enforcer.LoadPolicy()

9.2 事務(wù)回滾后策略未恢復(fù)

問題:在事務(wù)中更新策略,事務(wù)回滾后策略未恢復(fù)。

解決方案:確保在事務(wù)提交或回滾后,重新加載策略:

db.Transaction(func(tx *gorm.DB) error {
    enforcer := casbinx.GetEnforcer().SetDB(tx)
    // 更新策略
    return enforcer.EditPolicyPermissions(userName, policy)
})

// 事務(wù)提交或回滾后,重新加載策略
enforcer := casbinx.GetEnforcer()
enforcer.LoadPolicy()

9.3 路徑匹配問題

問題:使用 keyMatch3 函數(shù)時,路徑匹配不符合預(yù)期。

解決方案

  • keyMatch3 支持 * 通配符,如 /api/v1/user/* 可以匹配 /api/v1/user/list、/api/v1/user/detail
  • 如果需要更精確的匹配,可以使用 keyMatchregexMatch

?? 10. 最佳實(shí)踐

  1. 統(tǒng)一權(quán)限標(biāo)識格式:使用統(tǒng)一的前綴和分隔符,便于管理和維護(hù)
  2. 事務(wù)一致性:權(quán)限更新與業(yè)務(wù)數(shù)據(jù)更新應(yīng)在同一事務(wù)中
  3. 策略重新加載:策略更新后及時重新加載,確保權(quán)限檢查使用最新策略
  4. 錯誤處理:完善的錯誤處理和日志記錄,便于問題排查
  5. 性能優(yōu)化:策略加載到內(nèi)存后,權(quán)限檢查速度很快,但策略更新后需要重新加載

?? 總結(jié)

本文詳細(xì)介紹了如何在 Go 項(xiàng)目中使用 Casbin 實(shí)現(xiàn) RBAC 權(quán)限管理,包括:

  • ? Casbin 模型配置
  • ? Enforcer 初始化
  • ? 權(quán)限檢查中間件
  • ? 策略管理(權(quán)限策略和角色繼承)
  • ? 事務(wù)支持
  • ? 實(shí)際應(yīng)用場景
  • ? 常見問題與解決方案

基于本文的實(shí)現(xiàn),你可以快速構(gòu)建一個功能完整的權(quán)限管理系統(tǒng)。如果你需要完整的項(xiàng)目代碼,可以參考開源項(xiàng)目 gin-layout,這是一個功能完整的 Go Admin 后臺管理系統(tǒng)框架,提供了開箱即用的權(quán)限管理解決方案。

?? 相關(guān)資源

到此這篇關(guān)于Go項(xiàng)目中使用Casbin實(shí)現(xiàn)RBAC權(quán)限管理教程的文章就介紹到這了,更多相關(guān)Go RBAC 權(quán)限管理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 自定義Go?Json的序列化方法譯文

    自定義Go?Json的序列化方法譯文

    這篇文章主要為大家介紹了自定義Go?Json序列化方法譯文,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • 解決Goland 同一個package中函數(shù)互相調(diào)用的問題

    解決Goland 同一個package中函數(shù)互相調(diào)用的問題

    這篇文章主要介紹了解決Goland 同一個package中函數(shù)互相調(diào)用的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-05-05
  • 一文帶你徹底讀懂Go?1.24?map重構(gòu)了哪些

    一文帶你徹底讀懂Go?1.24?map重構(gòu)了哪些

    Go中的map是一種高效的內(nèi)置哈希表實(shí)現(xiàn),用于存儲鍵值對,了解map的底層實(shí)現(xiàn)原理對于編寫高性能的Go程序非常重要,這篇文章主要介紹了Go1.24 map重構(gòu)了哪些的相關(guān)資料,需要的朋友可以參考下
    2026-03-03
  • Golang通道阻塞情況與通道無阻塞實(shí)現(xiàn)小結(jié)

    Golang通道阻塞情況與通道無阻塞實(shí)現(xiàn)小結(jié)

    本文主要介紹了Golang通道阻塞情況與通道無阻塞實(shí)現(xiàn)小結(jié),詳細(xì)解析了通道的類型、操作方法以及垃圾回收機(jī)制,從基礎(chǔ)概念到高級應(yīng)用,具有一定的參考價值,感興趣的可以了解一下
    2024-03-03
  • golang多維度排序及題解最長連續(xù)序列

    golang多維度排序及題解最長連續(xù)序列

    這篇文章主要為大家介紹了golang多維度排序及題解最長連續(xù)序列示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-10-10
  • 深入理解Golang中Context的使用

    深入理解Golang中Context的使用

    本文主要介紹了Golang中Context的使用,特別是cancelCtx的實(shí)現(xiàn),通過理解cancelCtx的數(shù)據(jù)結(jié)構(gòu)、掛載機(jī)制和取消機(jī)制,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2026-02-02
  • Golang?websocket協(xié)議使用淺析

    Golang?websocket協(xié)議使用淺析

    這篇文章主要介紹了Golang?websocket協(xié)議的使用,WebSocket是一種新型的網(wǎng)絡(luò)通信協(xié)議,可以在Web應(yīng)用程序中實(shí)現(xiàn)雙向通信,感興趣想要詳細(xì)了解可以參考下文
    2023-05-05
  • go語言中的json與map相互轉(zhuǎn)換實(shí)現(xiàn)

    go語言中的json與map相互轉(zhuǎn)換實(shí)現(xiàn)

    本文主要介紹了go語言中的json與map相互轉(zhuǎn)換實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-08-08
  • golang bufio包中Write方法的深入講解

    golang bufio包中Write方法的深入講解

    這篇文章主要給大家介紹了關(guān)于golang bufio包中Write方法的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-02-02
  • Go?多環(huán)境下配置管理方案(多種方案)

    Go?多環(huán)境下配置管理方案(多種方案)

    這篇文章主要介紹了Go?多環(huán)境下配置管理方案,方案一配置文件管理,方案二集中式管理配置,每種方案給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-06-06

最新評論

静海县| 通山县| 登封市| 兴宁市| 亳州市| 鄢陵县| 桑植县| 万宁市| 南江县| 昌平区| 九龙县| 济宁市| 恩施市| 长宁区| 隆德县| 本溪| 顺平县| 化德县| 页游| 邮箱| 霍邱县| 丽江市| 廉江市| 裕民县| 石首市| 航空| 顺昌县| 杭州市| 揭东县| 津市市| 北辰区| 台南县| 建昌县| 夏津县| 临沧市| 察隅县| 闻喜县| 九江市| 江川县| 耒阳市| 怀集县|