feature/ip优化

This commit is contained in:
吕翠丽 2025-06-17 16:50:28 +08:00
parent 5574b1ba4e
commit 6d3891390f
5 changed files with 132 additions and 1 deletions

3
go.mod
View File

@ -5,8 +5,11 @@ go 1.18.0
require github.com/pkg/errors v0.9.1
require (
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/redis/go-redis/v9 v9.10.0 // indirect
github.com/stretchr/testify v1.10.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

6
go.sum
View File

@ -1,9 +1,15 @@
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/redis/go-redis/v9 v9.10.0 h1:FxwK3eV8p/CQa0Ch276C7u2d0eNC9kCmAYQ7mCXCzVs=
github.com/redis/go-redis/v9 v9.10.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

View File

@ -1,6 +1,7 @@
package ip_tool
import (
"context"
"encoding/json"
"fmt"
"io"
@ -15,12 +16,14 @@ import (
type HuaChenIpClient struct {
AppCode string
Host string
cache ICacheAdapter
}
func NewHuaChenIpClient(appCode string) *HuaChenIpClient {
func NewHuaChenIpClient(appCode string, cache ICacheAdapter) *HuaChenIpClient {
return &HuaChenIpClient{
AppCode: appCode,
Host: "https://c2ba.api.huachen.cn",
cache: cache,
}
}
@ -87,6 +90,31 @@ func (h *HuaChenIpClient) GetIpInfo(ip string) (res *ApiResult, err error) {
return &apiResult, nil
}
func (h *HuaChenIpClient) GetIpInfoFormCache(ctx context.Context, ip string) (res *ApiResult, err error) {
getCache, err := h.cache.Get(ctx, h.ipKey(ip))
if err != nil {
return nil, errors.Wrapf(err, "获取缓存失败ip:%s", ip)
}
if getCache != nil {
return getCache, nil
}
info, err := h.GetIpInfo(ip)
if err != nil {
return nil, errors.Wrapf(err, "获取ip:%s信息失败", ip)
}
err = h.cache.Set(ctx, h.ipKey(ip), *info, 24*time.Hour)
if err != nil {
return nil, errors.Wrapf(err, "缓存ip:%s信息失败", ip)
}
res = info
return
}
// ipKey 生成Redis key
func (h *HuaChenIpClient) ipKey(ip string) string {
return fmt.Sprintf("ip:%s", ip)
}
type ApiResult struct {
Ret int `json:"ret"`
Msg string `json:"msg"`

View File

@ -1,8 +1,14 @@
package ip_tool
import (
"context"
"encoding/json"
"fmt"
"github.com/pkg/errors"
"github.com/redis/go-redis/v9"
"log"
"testing"
"time"
)
func TestHuaChenIpClient_GetIpInfo(t *testing.T) {
@ -42,3 +48,78 @@ func TestHuaChenIpClient_GetIpInfo(t *testing.T) {
})
}
}
func TestHuaChenIpClient_GetIpInfo1(t *testing.T) {
rdb := redis.NewClient(&redis.Options{
Addr: "",
Password: "",
DB: 1,
})
// 创建IP缓存实例
ipCache := NewRedisCache(rdb)
h := &HuaChenIpClient{
AppCode: "",
Host: "https://c2ba.api.huachen.cn",
cache: ipCache,
}
gotRes, err := h.GetIpInfoFormCache(context.Background(), "8.138.116.112")
log.Println(gotRes, err)
}
type RedisCache struct {
client *redis.Client
}
func NewRedisCache(client *redis.Client) *RedisCache {
return &RedisCache{client: client}
}
func (r *RedisCache) Set(ctx context.Context, ip string, info ApiResult, ttl time.Duration) error {
if ip == "" {
return errors.New("ip不能为空")
}
data, err := json.Marshal(info)
if err != nil {
return fmt.Errorf("无法封送IP信息: %w", err)
}
return r.client.Set(ctx, ip, data, ttl).Err()
}
// Get 从Redis获取IP信息
func (r *RedisCache) Get(ctx context.Context, ip string) (*ApiResult, error) {
if ip == "" {
return nil, errors.New("ip不能为空")
}
data, err := r.client.Get(ctx, ip).Bytes()
if err != nil {
if errors.Is(err, redis.Nil) {
return nil, nil // 键不存在返回nil而不是错误
}
return nil, fmt.Errorf("无法获取IP信息: %w", err)
}
var info ApiResult
if err = json.Unmarshal(data, &info); err != nil {
return nil, fmt.Errorf("无法解析IP信息: %w", err)
}
return &info, nil
}
// Exists 检查IP是否存在缓存中
func (r *RedisCache) Exists(ctx context.Context, ip string) (bool, error) {
if ip == "" {
return false, errors.New("ip不能为空")
}
exists, err := r.client.Exists(ctx, ip).Result()
if err != nil {
return false, fmt.Errorf("无法检查IP是否存在: %w", err)
}
return exists > 0, nil
}

13
ip_tool/ip_cache.go Normal file
View File

@ -0,0 +1,13 @@
package ip_tool
import (
"context"
"time"
)
// Cache 定义缓存接口,遵循接口隔离原则
type ICacheAdapter interface {
Set(ctx context.Context, ip string, info ApiResult, ttl time.Duration) error
Get(ctx context.Context, ip string) (*ApiResult, error)
Exists(ctx context.Context, ip string) (bool, error)
}