亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

詳解在Go語(yǔ)言單元測(cè)試中如何解決Redis存儲(chǔ)依賴(lài)問(wèn)題

 更新時(shí)間:2023年08月07日 09:19:02   作者:江湖十年  
在編寫(xiě)單元測(cè)試時(shí),除了?MySQL?這個(gè)外部存儲(chǔ)依賴(lài),Redis?應(yīng)該是另一個(gè)最為常見(jiàn)的外部存儲(chǔ)依賴(lài)了,本文就來(lái)講解下如何解決?Redis?外部依賴(lài),文章通過(guò)代碼示例介紹的非常詳細(xì),需要的朋友可以參考下

登錄程序示例

在 Web 開(kāi)發(fā)中,登錄需求是一個(gè)較為常見(jiàn)的功能。假設(shè)我們有一個(gè) Login 函數(shù),可以實(shí)現(xiàn)用戶(hù)登錄功能。它接收用戶(hù)手機(jī)號(hào) + 短信驗(yàn)證碼,然后根據(jù)手機(jī)號(hào)從 Redis 中獲取保存的驗(yàn)證碼(驗(yàn)證碼通常是在發(fā)送驗(yàn)證碼這一操作時(shí)保存的),如果 Redis 中驗(yàn)證碼與用戶(hù)輸入的驗(yàn)證碼相同,則表示用戶(hù)信息正確,然后生成一個(gè)隨機(jī) token 作為登錄憑證,之后先將 token 寫(xiě)入 Redis 中,再返回給用戶(hù),表示登錄操作成功。

程序代碼實(shí)現(xiàn)如下:

func Login(mobile, smsCode string, rdb *redis.Client, generateToken func(int) (string, error)) (string, error) {
	ctx := context.Background()
	// 查找驗(yàn)證碼
	captcha, err := GetSmsCaptchaFromRedis(ctx, rdb, mobile)
	if err != nil {
		if err == redis.Nil {
			return "", fmt.Errorf("invalid sms code or expired")
		}
		return "", err
	}
	if captcha != smsCode {
		return "", fmt.Errorf("invalid sms code")
	}
	// 登錄,生成 token 并寫(xiě)入 Redis
	token, _ := generateToken(32)
	err = SetAuthTokenToRedis(ctx, rdb, token, mobile)
	if err != nil {
		return "", err
	}
	return token, nil
}

Login 函數(shù)有 4 個(gè)參數(shù),分別是用戶(hù)手機(jī)號(hào)、驗(yàn)證碼、Redis 客戶(hù)端連接對(duì)象、輔助生成隨機(jī) token 的函數(shù)。

Redis 客戶(hù)端連接對(duì)象 *redis.Client 屬于 github.com/redis/go-redis/v9 包。

我們可以使用如下方式獲得:

func NewRedisClient() *redis.Client {
	return redis.NewClient(&redis.Options{
		Addr:     "localhost:6379",
	})
}

generateToken 用來(lái)生成隨機(jī)長(zhǎng)度 token,定義如下:

func GenerateToken(length int) (string, error) {
	token := make([]byte, length)
	_, err := rand.Read(token)
	if err != nil {
		return "", err
	}
	return base64.URLEncoding.EncodeToString(token)[:length], nil
}

我們還要為 Redis 操作編寫(xiě)幾個(gè)函數(shù),用來(lái)存取 Redis 中的驗(yàn)證碼和 token:

var (
	smsCaptchaExpire    = 5 * time.Minute
	smsCaptchaKeyPrefix = "sms:captcha:%s"
	authTokenExpire    = 24 * time.Hour
	authTokenKeyPrefix = "auth:token:%s"
)
func SetSmsCaptchaToRedis(ctx context.Context, redis *redis.Client, mobile, captcha string) error {
	key := fmt.Sprintf(smsCaptchaKeyPrefix, mobile)
	return redis.Set(ctx, key, captcha, smsCaptchaExpire).Err()
}
func GetSmsCaptchaFromRedis(ctx context.Context, redis *redis.Client, mobile string) (string, error) {
	key := fmt.Sprintf(smsCaptchaKeyPrefix, mobile)
	return redis.Get(ctx, key).Result()
}
func SetAuthTokenToRedis(ctx context.Context, redis *redis.Client, token, mobile string) error {
	key := fmt.Sprintf(authTokenKeyPrefix, mobile)
	return redis.Set(ctx, key, token, authTokenExpire).Err()
}
func GetAuthTokenFromRedis(ctx context.Context, redis *redis.Client, token string) (string, error) {
	key := fmt.Sprintf(authTokenKeyPrefix, token)
	return redis.Get(ctx, key).Result()
}

Login 函數(shù)使用方式如下:

func main() {
	rdb := NewRedisClient()
	token, err := Login("13800001111", "123456", rdb, GenerateToken)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(token)
}

使用 redismock 測(cè)試

現(xiàn)在,我們要對(duì) Login 函數(shù)進(jìn)行單元測(cè)試。

Login 函數(shù)依賴(lài)了 *redis.Client 以及 generateToken 函數(shù)。

由于我們?cè)O(shè)計(jì)的代碼是 Login 函數(shù)直接依賴(lài)了 *redis.Client ,沒(méi)有通過(guò)接口來(lái)解耦,所以不能使用 gomock 工具來(lái)生成 Mock 代碼。

不過(guò),我們可以看看 go-redis 包的源碼倉(cāng)庫(kù)有沒(méi)有什么線(xiàn)索。

很幸運(yùn),在 go-redis 包的 README.md 文檔里,我們可以看到一個(gè) Redis Mock 鏈接:

image.png

點(diǎn)擊進(jìn)去,我們就來(lái)到了一個(gè)叫 redismock 的倉(cāng)庫(kù), redismock 為我們實(shí)現(xiàn)了一個(gè)模擬的 Redis 客戶(hù)端。

使用如下方式安裝 redismock

$ go get github.com/go-redis/redismock/v9 

使用如下方式導(dǎo)入 redismock

import "github.com/go-redis/redismock/v9" 

切記安裝和導(dǎo)入的 redismock 包版本要與 go-redis 包版本一致,這里都為 v9

可以通過(guò)如下方式快速創(chuàng)建一個(gè) Redis 客戶(hù)端 rdb ,以及客戶(hù)端 Mock 對(duì)象 mock

rdb, mock := redismock.NewClientMock() 

在測(cè)試代碼中,調(diào)用 Login 函數(shù)時(shí),就可以使用這個(gè) rdb 作為 Redis 客戶(hù)端了。

mock 對(duì)象提供了 ExpectXxx 方法,用來(lái)指定 rdb 客戶(hù)端預(yù)期會(huì)調(diào)用哪些方法以及對(duì)應(yīng)參數(shù)。

// login success
mock.ExpectGet("sms:captcha:13800138000").SetVal("123456")
mock.ExpectSet("auth:token:Ta5EVtRgUD-HFmRwrujAwKZnx247lFfe", "13800138000", 24*time.Hour).SetVal("OK")

mock.ExpectGet 表示期待一個(gè) Redis Get 操作,Key 為 sms:captcha:13800138000 , SetVal("123456") 用來(lái)設(shè)置當(dāng)前 Get 操作返回值為 123456 。

同理, mock.ExpectSet 表示期待一個(gè) Redis Set 操作,Key 為 auth:token:Ta5EVtRgUD-HFmRwrujAwKZnx247lFfe ,Value 為 13800138000 ,過(guò)期時(shí)間為 24*time.Hour ,返回 OK 表示這個(gè) Set 操作成功。

以上指定的兩個(gè)預(yù)期方法調(diào)用,是用來(lái)匹配 Login 成功時(shí)的用例。

Login 函數(shù)還有兩種失敗情況,當(dāng)通過(guò) GetSmsCaptchaFromRedis 函數(shù)查詢(xún) Redis 中驗(yàn)證碼不存在時(shí),返回 invalid sms code or expired 錯(cuò)誤。當(dāng)從 Redis 中查詢(xún)的驗(yàn)證碼與用戶(hù)傳遞進(jìn)來(lái)的驗(yàn)證碼不匹配時(shí),返回 invalid sms code 錯(cuò)誤。

這兩種用例可以按照如下方式模擬:

// invalid sms code or expired
mock.ExpectGet("sms:captcha:13900139000").RedisNil()
// invalid sms code
mock.ExpectGet("sms:captcha:13700137000").SetVal("123123")

現(xiàn)在,我們已經(jīng)解決了 Redis 依賴(lài),還需要解決 generateToken 函數(shù)依賴(lài)。

這時(shí)候 Fake object 就派上用場(chǎng)了:

func fakeGenerateToken(int) (string, error) {
	return "Ta5EVtRgUD-HFmRwrujAwKZnx247lFfe", nil
}

我們使用 fakeGenerateToken 函數(shù)來(lái)替代 GenerateToken 函數(shù),這樣生成的 token 就固定下來(lái)了,方便測(cè)試。

Login 函數(shù)完整單元測(cè)試代碼實(shí)現(xiàn)如下:

func TestLogin(t *testing.T) {
	// mock redis client
	rdb, mock := redismock.NewClientMock()
	// login success
	mock.ExpectGet("sms:captcha:13800138000").SetVal("123456")
	mock.ExpectSet("auth:token:Ta5EVtRgUD-HFmRwrujAwKZnx247lFfe", "13800138000", 24*time.Hour).SetVal("OK")
	// invalid sms code or expired
	mock.ExpectGet("sms:captcha:13900139000").RedisNil()
	// invalid sms code
	mock.ExpectGet("sms:captcha:13700137000").SetVal("123123")
	type args struct {
		mobile  string
		smsCode string
	}
	tests := []struct {
		name    string
		args    args
		want    string
		wantErr string
	}{
		{
			name: "login success",
			args: args{
				mobile:  "13800138000",
				smsCode: "123456",
			},
			want: "Ta5EVtRgUD-HFmRwrujAwKZnx247lFfe",
		},
		{
			name: "invalid sms code or expired",
			args: args{
				mobile:  "13900139000",
				smsCode: "123459",
			},
			wantErr: "invalid sms code or expired",
		},
		{
			name: "invalid sms code",
			args: args{
				mobile:  "13700137000",
				smsCode: "123457",
			},
			wantErr: "invalid sms code",
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got, err := Login(tt.args.mobile, tt.args.smsCode, rdb, fakeGenerateToken)
			if tt.wantErr != "" {
				assert.Error(t, err)
				assert.Equal(t, tt.wantErr, err.Error())
			} else {
				assert.NoError(t, err)
				assert.Equal(t, tt.want, got)
			}
		})
	}
}

這里使用了表格測(cè)試,提供了 3 個(gè)測(cè)試用例,覆蓋了登錄成功、驗(yàn)證碼無(wú)效或過(guò)期、驗(yàn)證碼無(wú)效 3 種場(chǎng)景。

使用 go test 來(lái)執(zhí)行測(cè)試函數(shù):

$ go test -v .                 
=== RUN   TestLogin
=== RUN   TestLogin/login_success
=== RUN   TestLogin/invalid_sms_code_or_expired
=== RUN   TestLogin/invalid_sms_code
--- PASS: TestLogin (0.00s)
    --- PASS: TestLogin/login_success (0.00s)
    --- PASS: TestLogin/invalid_sms_code_or_expired (0.00s)
    --- PASS: TestLogin/invalid_sms_code (0.00s)
PASS
ok      github.com/jianghushinian/blog-go-example/test/redis    0.152s

測(cè)試通過(guò)。

Login 函數(shù)將 *redis.Client generateToken 這兩個(gè)外部依賴(lài)定義成了函數(shù)參數(shù),而不是在函數(shù)內(nèi)部直接使用這兩個(gè)依賴(lài)。

這主要參考了「依賴(lài)注入」的思想,將依賴(lài)當(dāng)作參數(shù)傳入,而不是在函數(shù)內(nèi)部直接引用。

這樣,我們才有機(jī)會(huì)使用 Fake 對(duì)象 fakeGenerateToken 來(lái)替代真實(shí)對(duì)象 GenerateToken 。

而對(duì)于 *redis.Client ,我們也能夠使用 redismock 提供的 Mock 對(duì)象來(lái)替代。

redismock 不僅能夠模擬 RedisClient,它還支持模擬 RedisCluster,更多使用示例可以在官方示例中查看。

使用 Testcontainers 測(cè)試

雖然我們使用 redismock 提供的 Mock 對(duì)象解決了 Login 函數(shù)對(duì) *redis.Client 的依賴(lài)問(wèn)題。

但這需要運(yùn)氣,當(dāng)我們使用其他數(shù)據(jù)庫(kù)時(shí),也許找不到現(xiàn)成的 Mock 庫(kù)。

此時(shí),我們還有另一個(gè)強(qiáng)大的工具「容器」可以使用。

如果程序所依賴(lài)的某個(gè)外部服務(wù),實(shí)在找不到現(xiàn)成的 Mock 工具,自己實(shí)現(xiàn) Fack object 又比較麻煩,這時(shí)就可以考慮使用容器來(lái)運(yùn)行一個(gè)真正的外部服務(wù)了。

Testcontainers 就是用來(lái)解決這個(gè)問(wèn)題的,我們可以用它來(lái)啟動(dòng)容器,運(yùn)行任何外部服務(wù)。

Testcontainers 非常強(qiáng)大,不僅支持 Go 語(yǔ)言,還支持 Java、Python、Rust 等其他主流編程語(yǔ)言。它可以很容易地創(chuàng)建和清理基于容器的依賴(lài),常被用于集成測(cè)試和冒煙測(cè)試。所以這也提醒我們?cè)趩卧獪y(cè)試中慎用,因?yàn)槿萜饕彩且粋€(gè)外部依賴(lài)。

我們可以按照如下方式使用 Testcontainers 在容器中啟動(dòng)一個(gè) Redis 服務(wù):

import (
	"context"
	"fmt"
	"github.com/redis/go-redis/v9"
	"github.com/testcontainers/testcontainers-go"
	"github.com/testcontainers/testcontainers-go/wait"
)
// 在容器中運(yùn)行一個(gè) Redis 服務(wù)
func RunWithRedisInContainer() (*redis.Client, func()) {
	ctx := context.Background()
	// 創(chuàng)建容器請(qǐng)求參數(shù)
	req := testcontainers.ContainerRequest{
		Image:        "redis:6.0.20-alpine",                      // 指定容器鏡像
		ExposedPorts: []string{"6379/tcp"},                       // 指定容器暴露端口
		WaitingFor:   wait.ForLog("Ready to accept connections"), // 等待輸出容器 Ready 日志
	}
	// 創(chuàng)建 Redis 容器
	redisC, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
		ContainerRequest: req,
		Started:          true,
	})
	if err != nil {
		panic(fmt.Sprintf("failed to start container: %s", err.Error()))
	}
	// 獲取容器中 Redis 連接地址,e.g. localhost:50351
	endpoint, err := redisC.Endpoint(ctx, "") // 如果暴露多個(gè)端口,可以指定第二個(gè)參數(shù)
	if err != nil {
		panic(fmt.Sprintf("failed to get endpoint: %s", err.Error()))
	}
	// 連接容器中的 Redis
	client := redis.NewClient(&redis.Options{
		Addr: endpoint,
	})
	// 返回 Redis Client 和 cleanup 函數(shù)
	return client, func() {
		if err := redisC.Terminate(ctx); err != nil {
			panic(fmt.Sprintf("failed to terminate container: %s", err.Error()))
		}
	}
}

代碼中我寫(xiě)了比較詳細(xì)的注釋?zhuān)筒粠Т蠹乙灰唤忉尨a內(nèi)容了。

我們可以將容器的啟動(dòng)和釋放操作放到 TestMain 函數(shù)中,這樣在執(zhí)行測(cè)試函數(shù)之前先啟動(dòng)容器,然后進(jìn)行測(cè)試,最后在測(cè)試結(jié)束時(shí)銷(xiāo)毀容器。

var rdbClient *redis.Client
func TestMain(m *testing.M) {
	client, f := RunWithRedisInContainer()
	defer f()
	rdbClient = client
	m.Run()
}

使用容器編寫(xiě)的 Login 單元測(cè)試函數(shù)如下:

func TestLogin_by_container(t *testing.T) {
	// 準(zhǔn)備測(cè)試數(shù)據(jù)
	err := SetSmsCaptchaToRedis(context.Background(), rdbClient, "18900001111", "123456")
	assert.NoError(t, err)
	// 測(cè)試登錄成功情況
	gotToken, err := Login("18900001111", "123456", rdbClient, GenerateToken)
	assert.NoError(t, err)
	assert.Equal(t, 32, len(gotToken))
	// 檢查 Redis 中是否存在 token
	gotMobile, err := GetAuthTokenFromRedis(context.Background(), rdbClient, gotToken)
	assert.NoError(t, err)
	assert.Equal(t, "18900001111", gotMobile)
}

現(xiàn)在因?yàn)橛辛巳萜鞯拇嬖?,我們有了一個(gè)真實(shí)的 Redis 服務(wù)。所以編寫(xiě)測(cè)試代碼時(shí),無(wú)需再考慮如何模擬 Redis 客戶(hù)端,只需要使用通過(guò) RunWithRedisInContainer() 函數(shù)創(chuàng)建的真實(shí)客戶(hù)端 rdbClient 即可,一切操作都是真實(shí)的。

并且,我們也不再需要實(shí)現(xiàn) fakeGenerateToken 函數(shù)來(lái)固定生成的 token,直接使用 GenerateToken 生成真實(shí)的隨機(jī) token 即可。想要驗(yàn)證得到的 token 是否正確,可以直接從 Redis 服務(wù)中讀取。

執(zhí)行測(cè)試前,確保主機(jī)上已經(jīng)安裝了 Docker, Testcontainers 會(huì)使用主機(jī)上的 Docker 來(lái)運(yùn)行容器。

使用 go test 來(lái)執(zhí)行測(cè)試函數(shù):

$ go test -v -run="TestLogin_by_container"
2023/07/17 22:59:34 github.com/testcontainers/testcontainers-go - Connected to docker: 
  Server Version: 20.10.21
  API Version: 1.41
  Operating System: Docker Desktop
  Total Memory: 7851 MB
2023/07/17 22:59:34 ?? Creating container for image docker.io/testcontainers/ryuk:0.5.1
2023/07/17 22:59:34 ? Container created: 92e327ad7b70
2023/07/17 22:59:34 ?? Starting container: 92e327ad7b70
2023/07/17 22:59:35 ? Container started: 92e327ad7b70
2023/07/17 22:59:35 ?? Waiting for container id 92e327ad7b70 image: docker.io/testcontainers/ryuk:0.5.1. Waiting for: &{Port:8080/tcp timeout:<nil> PollInterval:100ms}
2023/07/17 22:59:35 ?? Creating container for image redis:6.0.20-alpine
2023/07/17 22:59:35 ? Container created: 2b5e40d40af0
2023/07/17 22:59:35 ?? Starting container: 2b5e40d40af0
2023/07/17 22:59:35 ? Container started: 2b5e40d40af0
2023/07/17 22:59:35 ?? Waiting for container id 2b5e40d40af0 image: redis:6.0.20-alpine. Waiting for: &{timeout:<nil> Log:Ready to accept connections Occurrence:1 PollInterval:100ms}
=== RUN   TestLogin_by_container
--- PASS: TestLogin_by_container (0.00s)
PASS
2023/07/17 22:59:36 ?? Terminating container: 2b5e40d40af0
2023/07/17 22:59:36 ?? Container terminated: 2b5e40d40af0
ok      github.com/jianghushinian/blog-go-example/test/redis    1.545s

測(cè)試通過(guò)。

根據(jù)輸出日志可以發(fā)現(xiàn),我們的確在主機(jī)上創(chuàng)建了一個(gè) Redis 容器來(lái)運(yùn)行 Redis 服務(wù):

Creating container for image redis:6.0.20-alpine 

容器 ID 為 2b5e40d40af0

Container created: 2b5e40d40af0 

并且測(cè)試結(jié)束后清理了容器:

Container terminated: 2b5e40d40af0 

以上,我們就利用容器技術(shù),為 Login 函數(shù)登錄成功情況編寫(xiě)了一個(gè)測(cè)試用例,登錄失敗情況的測(cè)試用例就留做作業(yè)交給你自己來(lái)完成吧。

總結(jié)

本文向大家介紹了在 Go 中編寫(xiě)單元測(cè)試時(shí),如何解決 Redis 外部依賴(lài)的問(wèn)題。

值得慶幸的是 redismock 包提供了模擬的 Redis 客戶(hù)端,方便我們?cè)跍y(cè)試過(guò)程中替換 Redis 外部依賴(lài)。

但有些時(shí)候,我們可能找不到這種現(xiàn)成的第三方包。 Testcontainers 庫(kù)則為我們提供了另一種解決方案,運(yùn)行一個(gè)真實(shí)的容器,以此來(lái)提供 Redis 服務(wù)。

不過(guò),雖然 Testcontainers 足夠強(qiáng)大,但不到萬(wàn)不得已,不推薦使用。畢竟我們又引入了容器這個(gè)外部依賴(lài),如果網(wǎng)絡(luò)情況不好,如何拉取 Redis 鏡像也是需要解決的問(wèn)題。

更好的解決辦法,是我們?cè)诰帉?xiě)代碼時(shí),就要考慮如何寫(xiě)出可測(cè)試的代碼,好的代碼設(shè)計(jì),能夠大大降低編寫(xiě)測(cè)試的難度。

以上就是詳解在Go語(yǔ)言單元測(cè)試中如何解決Redis存儲(chǔ)依賴(lài)問(wèn)題的詳細(xì)內(nèi)容,更多關(guān)于Go單元測(cè)試解決Redis存儲(chǔ)依賴(lài)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Go Module依賴(lài)管理的實(shí)現(xiàn)

    Go Module依賴(lài)管理的實(shí)現(xiàn)

    Go Module是Go語(yǔ)言的官方依賴(lài)管理解決方案,其提供了一種簡(jiǎn)單、可靠的方式來(lái)管理項(xiàng)目的依賴(lài)關(guān)系,本文主要介紹了Go Module依賴(lài)管理的實(shí)現(xiàn),感興趣的可以了解一下
    2024-06-06
  • go select的用法

    go select的用法

    本文主要介紹了go select的用法,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • go語(yǔ)言fasthttp使用實(shí)例小結(jié)

    go語(yǔ)言fasthttp使用實(shí)例小結(jié)

    fasthttp?是一個(gè)使用?Go?語(yǔ)言開(kāi)發(fā)的?HTTP?包,主打高性能,針對(duì)?HTTP?請(qǐng)求響應(yīng)流程中的?hot?path?代碼進(jìn)行了優(yōu)化,下面我們就來(lái)介紹go語(yǔ)言fasthttp使用實(shí)例小結(jié),感興趣的朋友跟隨小編一起看看吧
    2024-03-03
  • 詳解Go語(yǔ)言中關(guān)于包導(dǎo)入必學(xué)的 8 個(gè)知識(shí)點(diǎn)

    詳解Go語(yǔ)言中關(guān)于包導(dǎo)入必學(xué)的 8 個(gè)知識(shí)點(diǎn)

    這篇文章主要介紹了詳解Go語(yǔ)言中關(guān)于包導(dǎo)入必學(xué)的 8 個(gè)知識(shí)點(diǎn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • Go基礎(chǔ)系列:Go切片(分片)slice詳解

    Go基礎(chǔ)系列:Go切片(分片)slice詳解

    這篇文章主要介紹了Go語(yǔ)言中的切片(分片)slice詳細(xì)說(shuō)明?,需要的朋友可以參考下
    2022-04-04
  • 詳解Go語(yǔ)言中select語(yǔ)句的常見(jiàn)用法

    詳解Go語(yǔ)言中select語(yǔ)句的常見(jiàn)用法

    這篇文章主要是來(lái)和大家介紹一下Go語(yǔ)言中select?語(yǔ)句的常見(jiàn)用法,以及在使用過(guò)程中的注意事項(xiàng),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下
    2023-07-07
  • go實(shí)現(xiàn)redigo的簡(jiǎn)單操作

    go實(shí)現(xiàn)redigo的簡(jiǎn)單操作

    golang操作redis主要有兩個(gè)庫(kù),go-redis和redigo,今天我們就一起來(lái)介紹一下redigo的實(shí)現(xiàn)方法,需要的朋友可以參考下
    2018-07-07
  • Go實(shí)現(xiàn)自己的網(wǎng)絡(luò)流量解析和行為檢測(cè)引擎原理

    Go實(shí)現(xiàn)自己的網(wǎng)絡(luò)流量解析和行為檢測(cè)引擎原理

    這篇文章主要為大家介紹了Go實(shí)現(xiàn)自己的網(wǎng)絡(luò)流量解析和行為檢測(cè)引擎原理,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-11-11
  • go基于Gin框架的HTTP接口限速實(shí)踐

    go基于Gin框架的HTTP接口限速實(shí)踐

    HTTP接口在各個(gè)業(yè)務(wù)模塊之間扮演著重要的角色,本文主要介紹了go基于Gin框架的HTTP接口限速實(shí)踐,具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-09-09
  • Go語(yǔ)言colly框架的快速入門(mén)

    Go語(yǔ)言colly框架的快速入門(mén)

    Python?中非常知名的爬蟲(chóng)框架有Scrapy,Go?中也有一些?star?數(shù)較高的爬蟲(chóng)框架,colly就是其中的佼佼者,它?API?簡(jiǎn)潔,性能優(yōu)良,開(kāi)箱即用,今天就來(lái)快速學(xué)習(xí)一下吧
    2023-07-07

最新評(píng)論