新增IP地址显示

This commit is contained in:
537yaha
2026-05-18 19:23:53 +08:00
parent f1e488e660
commit 8effb7e178
6 changed files with 65 additions and 33 deletions
+3 -3
View File
@@ -69,11 +69,11 @@ REDIS_WS_CHANNEL=ai_cs:ws_events
# =========================
# 访客 IP 地理位置(ip2region 离线库,可选)
# =========================
# true 时关闭解析;Docker 镜像内已内置 data/ip2region_v4.xdb
# true 时关闭解析;Docker 镜像内已内置 v4+v6 数据文件
IP2REGION_DISABLED=false
# 自定义 xdb 路径(本地开发可下载到 backend/data/,见 backend/data/README.md
# 自定义 xdb 路径(本地开发sh scripts/download-ip2region-xdb.sh
# IP2REGION_V4_XDB=backend/data/ip2region_v4.xdb
# IP2REGION_V6_XDB=
# IP2REGION_V6_XDB=backend/data/ip2region_v6.xdb
# =========================
# 端口映射(非必须)
+6 -2
View File
@@ -18,8 +18,11 @@ RUN go mod download
COPY . .
# 离线 IP 库(访客地理位置,见 backend/data/README.md
RUN mkdir -p data && curl -fsSL -o data/ip2region_v4.xdb \
https://github.com/lionsoul2014/ip2region/raw/master/data/ip2region_v4.xdb
RUN mkdir -p data && \
curl -fsSL -o data/ip2region_v4.xdb \
https://github.com/lionsoul2014/ip2region/raw/master/data/ip2region_v4.xdb && \
curl -fsSL -o data/ip2region_v6.xdb \
https://github.com/lionsoul2014/ip2region/raw/master/data/ip2region_v6.xdb
# 构建应用
# CGO_ENABLED=0: 禁用 CGO,生成纯 Go 二进制文件
@@ -42,6 +45,7 @@ COPY --from=builder /app/backend .
# ip2region 数据文件
COPY --from=builder /app/data/ip2region_v4.xdb /app/data/ip2region_v4.xdb
COPY --from=builder /app/data/ip2region_v6.xdb /app/data/ip2region_v6.xdb
# 从构建阶段复制时区数据(可选)
COPY --from=builder /usr/share/zoneinfo /usr/share/zoneinfo
+4 -6
View File
@@ -4,16 +4,14 @@
## 获取数据文件
**`ip2region_v4.xdb`** 放到本目录(与本文档同级)
**`ip2region_v4.xdb`****`ip2region_v6.xdb`** 放到本目录(与本文档同级)
访客 IP 若为 **IPv6**(如 `2403:...`),必须提供 v6 库才能显示位置。
```bash
# 在项目根目录执行(需 curl
curl -L -o backend/data/ip2region_v4.xdb \
https://github.com/lionsoul2014/ip2region/raw/master/data/ip2region_v4.xdb
# 在项目根目录执行(推荐脚本,一次下齐 v4+v6
sh scripts/download-ip2region-xdb.sh
```
可选 IPv6:下载 `ip2region_v6.xdb` 并设置环境变量 `IP2REGION_V6_XDB`
## 环境变量
| 变量 | 说明 |
+26 -11
View File
@@ -86,10 +86,13 @@ func InitFromEnv() {
v4Path := strings.TrimSpace(os.Getenv("IP2REGION_V4_XDB"))
v6Path := strings.TrimSpace(os.Getenv("IP2REGION_V6_XDB"))
if v4Path == "" {
v4Path = findDefaultV4XDB()
v4Path = findDefaultXDB("ip2region_v4.xdb")
}
if v4Path == "" {
log.Println("⚠️ 未找到 ip2region xdb 文件,访客「位置」将保持为空;可将 data/ip2region_v4.xdb 放到 backend/data/ 或设置 IP2REGION_V4_XDB")
if v6Path == "" {
v6Path = findDefaultXDB("ip2region_v6.xdb")
}
if v4Path == "" && v6Path == "" {
log.Println("⚠️ 未找到 ip2region xdb,访客「位置」将保持为空;请放置 backend/data/ip2region_v4.xdb(及可选 v6)或设置 IP2REGION_V4_XDB / IP2REGION_V6_XDB")
return
}
@@ -99,22 +102,34 @@ func InitFromEnv() {
return
}
globalResolver = &ip2regionResolver{svc: svc}
log.Printf("✅ ip2region 已加载 (v4: %s)", v4Path)
if v4Path != "" {
log.Printf("✅ ip2region 已加载 (v4: %s)", v4Path)
}
if v6Path != "" {
log.Printf(" IPv6 库: %s", v6Path)
log.Printf("✅ ip2region 已加载 (v6: %s)", v6Path)
} else {
log.Println("️ 未加载 ip2region IPv6 库;访客若为 IPv6 地址将无法解析位置,可下载 ip2region_v6.xdb")
}
}
func findDefaultV4XDB() string {
// LookupLocation 解析 IP;已有 location 非空时原样返回。
func LookupLocation(ip, currentLocation string) string {
if strings.TrimSpace(currentLocation) != "" {
return currentLocation
}
return Get().Lookup(ip)
}
func findDefaultXDB(filename string) string {
candidates := []string{
"data/ip2region_v4.xdb",
"backend/data/ip2region_v4.xdb",
"/app/data/ip2region_v4.xdb",
"data/" + filename,
"backend/data/" + filename,
"/app/data/" + filename,
}
if wd, err := os.Getwd(); err == nil {
candidates = append(candidates,
filepath.Join(wd, "data", "ip2region_v4.xdb"),
filepath.Join(wd, "..", "backend", "data", "ip2region_v4.xdb"),
filepath.Join(wd, "data", filename),
filepath.Join(wd, "..", "backend", "data", filename),
)
}
for _, p := range candidates {
+17 -5
View File
@@ -109,7 +109,7 @@ func (s *ConversationService) InitConversation(input InitConversationInput) (*In
OS: input.OS,
Language: input.Language,
IPAddress: input.IPAddress,
Location: geoip.Get().Lookup(input.IPAddress),
Location: geoip.LookupLocation(input.IPAddress, ""),
LastSeenAt: &now,
ChatMode: chatMode,
AIConfigID: aiConfigID,
@@ -161,10 +161,15 @@ func (s *ConversationService) InitConversation(input InitConversationInput) (*In
}
if input.IPAddress != "" && conv.IPAddress == "" {
updates["ip_address"] = input.IPAddress
if conv.Location == "" {
if loc := geoip.Get().Lookup(input.IPAddress); loc != "" {
updates["location"] = loc
}
}
// 补全地理位置:新 IP、或历史会话仅有 IP 无 location(如升级前创建、或当时缺 v6 库)
ipForGeo := conv.IPAddress
if input.IPAddress != "" {
ipForGeo = input.IPAddress
}
if conv.Location == "" && ipForGeo != "" {
if loc := geoip.LookupLocation(ipForGeo, ""); loc != "" {
updates["location"] = loc
}
}
@@ -432,6 +437,13 @@ func (s *ConversationService) GetConversationDetail(id uint, userID uint) (*Conv
return nil, gorm.ErrRecordNotFound
}
if conv.Location == "" && conv.IPAddress != "" {
if loc := geoip.LookupLocation(conv.IPAddress, ""); loc != "" {
_ = s.conversations.UpdateFields(conv.ID, map[string]interface{}{"location": loc})
conv.Location = loc
}
}
summary, err := s.buildSummary(*conv, userID)
if err != nil {
return nil, err
+9 -6
View File
@@ -1,9 +1,12 @@
#!/usr/bin/env sh
# 下载 ip2region v4 xdb 到 backend/data/(本地开发用)
# 下载 ip2region v4/v6 xdb 到 backend/data/(本地开发用)
set -e
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
DEST="$ROOT/backend/data/ip2region_v4.xdb"
mkdir -p "$(dirname "$DEST")"
curl -fsSL -o "$DEST" \
https://github.com/lionsoul2014/ip2region/raw/master/data/ip2region_v4.xdb
echo "OK: $DEST ($(wc -c < "$DEST" | tr -d ' ') bytes)"
DIR="$ROOT/backend/data"
mkdir -p "$DIR"
BASE="https://github.com/lionsoul2014/ip2region/raw/master/data"
for f in ip2region_v4.xdb ip2region_v6.xdb; do
DEST="$DIR/$f"
curl -fsSL -o "$DEST" "$BASE/$f"
echo "OK: $DEST ($(wc -c < "$DEST" | tr -d ' ') bytes)"
done