Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6097209c48 | |||
| 1835faddc0 | |||
| 0ddc2f17b9 | |||
| 91359f61ac | |||
| e1829b90bf | |||
| 6980b31da7 | |||
| 4960021748 |
@@ -251,7 +251,7 @@ func GetInstanceAddr(ctx context.Context, name string) (addr string, err error)
|
|||||||
err = errors.New("获取服务监听器失败")
|
err = errors.New("获取服务监听器失败")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
defer watch.Close()
|
||||||
service, err := watch.Proceed()
|
service, err := watch.Proceed()
|
||||||
if err != nil || service == nil {
|
if err != nil || service == nil {
|
||||||
err = errors.New("获取服务实例失败")
|
err = errors.New("获取服务实例失败")
|
||||||
|
|||||||
@@ -7,10 +7,11 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gitea.com/red-future/common/beans"
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
"gitea.com/red-future/common/utils"
|
"gitea.redpowerfuture.com/red-future/common/utils"
|
||||||
"github.com/bwmarrin/snowflake"
|
"github.com/bwmarrin/snowflake"
|
||||||
"github.com/gogf/gf/v2/crypto/gmd5"
|
"github.com/gogf/gf/v2/crypto/gmd5"
|
||||||
"github.com/gogf/gf/v2/database/gdb"
|
"github.com/gogf/gf/v2/database/gdb"
|
||||||
@@ -27,9 +28,30 @@ import (
|
|||||||
// ==================== 缓存管理器(单例) ====================
|
// ==================== 缓存管理器(单例) ====================
|
||||||
|
|
||||||
var (
|
var (
|
||||||
localCache *gcache.Cache
|
localCache *gcache.Cache
|
||||||
|
snowflakeNode *snowflake.Node
|
||||||
|
snowflakeOnce sync.Once
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
ctx := context.Background()
|
||||||
|
snowflakeOnce.Do(func() {
|
||||||
|
nodeId := genv.Get("APP_NODE", 1).Int64()
|
||||||
|
// 安全范围 0~1023
|
||||||
|
if nodeId < 0 || nodeId > 1023 {
|
||||||
|
nodeId = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
node, err := snowflake.NewNode(nodeId)
|
||||||
|
if err != nil {
|
||||||
|
g.Log().Errorf(ctx, "snowflake init failed: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
snowflakeNode = node
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// getLocalCache 获取本地缓存实例
|
// getLocalCache 获取本地缓存实例
|
||||||
func getLocalCache() *gcache.Cache {
|
func getLocalCache() *gcache.Cache {
|
||||||
if localCache == nil {
|
if localCache == nil {
|
||||||
@@ -165,18 +187,13 @@ func insertHook(ctx context.Context, in *gdb.HookInsertInput) (result sql.Result
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
nodeId := genv.Get("APP_NODE", "").Int64()
|
if g.IsEmpty(snowflakeNode) {
|
||||||
if g.IsEmpty(nodeId) {
|
return nil, fmt.Errorf("snowflakeNode is nil")
|
||||||
nodeId = 1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
node, err := snowflake.NewNode(nodeId)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
for i := range in.Data {
|
for i := range in.Data {
|
||||||
if _, ok := in.Data[i]["id"]; ok {
|
if _, ok := in.Data[i]["id"]; ok {
|
||||||
in.Data[i]["id"] = node.Generate().Int64()
|
in.Data[i]["id"] = snowflakeNode.Generate().Int64()
|
||||||
}
|
}
|
||||||
if _, ok := in.Data[i]["tenant_id"]; ok {
|
if _, ok := in.Data[i]["tenant_id"]; ok {
|
||||||
if g.IsEmpty(in.Data[i]["tenant_id"]) {
|
if g.IsEmpty(in.Data[i]["tenant_id"]) {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gitea.com/red-future/common/log/consts"
|
"gitea.redpowerfuture.com/red-future/common/log/consts"
|
||||||
|
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
"github.com/gogf/gf/v2/os/glog"
|
"github.com/gogf/gf/v2/os/glog"
|
||||||
|
|||||||
@@ -11,12 +11,12 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gitea.com/red-future/common/log/consts"
|
"gitea.redpowerfuture.com/red-future/common/log/consts"
|
||||||
"go.mongodb.org/mongo-driver/v2/event"
|
"go.mongodb.org/mongo-driver/v2/event"
|
||||||
|
|
||||||
"gitea.com/red-future/common/beans"
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
"gitea.com/red-future/common/log/model/entity"
|
"gitea.redpowerfuture.com/red-future/common/log/model/entity"
|
||||||
"gitea.com/red-future/common/utils"
|
"gitea.redpowerfuture.com/red-future/common/utils"
|
||||||
"github.com/gogf/gf/v2/container/gvar"
|
"github.com/gogf/gf/v2/container/gvar"
|
||||||
"github.com/gogf/gf/v2/errors/gerror"
|
"github.com/gogf/gf/v2/errors/gerror"
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gitea.com/red-future/common/beans"
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
"gitea.com/red-future/common/utils"
|
"gitea.redpowerfuture.com/red-future/common/utils"
|
||||||
"github.com/gogf/gf/v2/container/gvar"
|
"github.com/gogf/gf/v2/container/gvar"
|
||||||
"github.com/gogf/gf/v2/errors/gerror"
|
"github.com/gogf/gf/v2/errors/gerror"
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
|
|||||||
3
go.mod
3
go.mod
@@ -1,5 +1,4 @@
|
|||||||
module gitea.com/red-future/common
|
module gitea.redpowerfuture.com/red-future/common
|
||||||
|
|
||||||
go 1.26.0
|
go 1.26.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ import (
|
|||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
_ "gitea.com/red-future/common/consul"
|
_ "gitea.redpowerfuture.com/red-future/common/consul"
|
||||||
"gitea.com/red-future/common/jaeger"
|
"gitea.redpowerfuture.com/red-future/common/jaeger"
|
||||||
"gitea.com/red-future/common/utils"
|
"gitea.redpowerfuture.com/red-future/common/utils"
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
"github.com/gogf/gf/v2/net/gclient"
|
"github.com/gogf/gf/v2/net/gclient"
|
||||||
"github.com/gogf/gf/v2/net/ghttp"
|
"github.com/gogf/gf/v2/net/ghttp"
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ package controller
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"gitea.com/red-future/common/log/model/dto"
|
"gitea.redpowerfuture.com/red-future/common/log/model/dto"
|
||||||
"gitea.com/red-future/common/log/service"
|
"gitea.redpowerfuture.com/red-future/common/log/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
type operationLog struct{}
|
type operationLog struct{}
|
||||||
|
|||||||
@@ -3,15 +3,15 @@ package dao
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"gitea.com/red-future/common/beans"
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
"gitea.com/red-future/common/db/mongo"
|
"gitea.redpowerfuture.com/red-future/common/db/mongo"
|
||||||
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gitea.com/red-future/common/log/consts"
|
"gitea.redpowerfuture.com/red-future/common/log/consts"
|
||||||
"gitea.com/red-future/common/log/model/dto"
|
"gitea.redpowerfuture.com/red-future/common/log/model/dto"
|
||||||
"gitea.com/red-future/common/log/model/entity"
|
"gitea.redpowerfuture.com/red-future/common/log/model/entity"
|
||||||
"go.mongodb.org/mongo-driver/v2/bson"
|
"go.mongodb.org/mongo-driver/v2/bson"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package dto
|
package dto
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"gitea.com/red-future/common/beans"
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
"github.com/gogf/gf/v2/os/gtime"
|
"github.com/gogf/gf/v2/os/gtime"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package entity
|
package entity
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"gitea.com/red-future/common/beans"
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
)
|
)
|
||||||
|
|
||||||
// OperationLog 操作日志实体 - 用于记录数据增删改操作行为
|
// OperationLog 操作日志实体 - 用于记录数据增删改操作行为
|
||||||
|
|||||||
@@ -2,11 +2,11 @@ package service
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"gitea.com/red-future/common/beans"
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
"gitea.com/red-future/common/log/dao"
|
"gitea.redpowerfuture.com/red-future/common/log/dao"
|
||||||
"gitea.com/red-future/common/log/model/dto"
|
"gitea.redpowerfuture.com/red-future/common/log/model/dto"
|
||||||
logEntity "gitea.com/red-future/common/log/model/entity"
|
logEntity "gitea.redpowerfuture.com/red-future/common/log/model/entity"
|
||||||
"gitea.com/red-future/common/utils"
|
"gitea.redpowerfuture.com/red-future/common/utils"
|
||||||
"github.com/gogf/gf/v2/util/gconv"
|
"github.com/gogf/gf/v2/util/gconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gitea.com/red-future/common/utils"
|
"gitea.redpowerfuture.com/red-future/common/utils"
|
||||||
"github.com/alibaba/sentinel-golang/api"
|
"github.com/alibaba/sentinel-golang/api"
|
||||||
"github.com/alibaba/sentinel-golang/core/circuitbreaker"
|
"github.com/alibaba/sentinel-golang/core/circuitbreaker"
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"gitea.com/red-future/common/beans"
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
commonHttp "gitea.com/red-future/common/http"
|
commonHttp "gitea.redpowerfuture.com/red-future/common/http"
|
||||||
"gitea.com/red-future/common/utils"
|
"gitea.redpowerfuture.com/red-future/common/utils"
|
||||||
"github.com/gogf/gf/v2/database/gredis"
|
"github.com/gogf/gf/v2/database/gredis"
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
"github.com/gogf/gf/v2/net/ghttp"
|
"github.com/gogf/gf/v2/net/ghttp"
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"gitea.com/red-future/common/utils"
|
"gitea.redpowerfuture.com/red-future/common/utils"
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
"github.com/gogf/gf/v2/net/ghttp"
|
"github.com/gogf/gf/v2/net/ghttp"
|
||||||
"github.com/gogf/gf/v2/util/gconv"
|
"github.com/gogf/gf/v2/util/gconv"
|
||||||
@@ -92,7 +92,7 @@ func UserLimiter(r *ghttp.Request) {
|
|||||||
var userName string
|
var userName string
|
||||||
user, err := utils.GetUserInfo(r.GetCtx())
|
user, err := utils.GetUserInfo(r.GetCtx())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.Response.WriteStatusExit(429, err.Error())
|
r.Response.WriteStatusExit(401, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
userName = gconv.String(user.UserName)
|
userName = gconv.String(user.UserName)
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ package swagger
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"gitea.com/red-future/common/consul"
|
"gitea.redpowerfuture.com/red-future/common/consul"
|
||||||
"gitea.com/red-future/common/http"
|
"gitea.redpowerfuture.com/red-future/common/http"
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
"github.com/gogf/gf/v2/net/ghttp"
|
"github.com/gogf/gf/v2/net/ghttp"
|
||||||
"github.com/gogf/gf/v2/util/gconv"
|
"github.com/gogf/gf/v2/util/gconv"
|
||||||
|
|||||||
44
utils/gse.go
44
utils/gse.go
@@ -2,6 +2,8 @@ package utils
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"sort"
|
"sort"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
@@ -54,7 +56,24 @@ func newGseTool() (tool *gseTool, err error) {
|
|||||||
// 2. 初始化 TF-IDF 提取器
|
// 2. 初始化 TF-IDF 提取器
|
||||||
tfidf := &extracker.TagExtracter{}
|
tfidf := &extracker.TagExtracter{}
|
||||||
tfidf.WithGse(seg)
|
tfidf.WithGse(seg)
|
||||||
err = tfidf.LoadIdf()
|
|
||||||
|
// 尝试从默认路径加载 IDF 字典
|
||||||
|
idfPath := getIdfDictPath()
|
||||||
|
if idfPath != "" {
|
||||||
|
// 如果找到自定义路径,使用 LoadDict 方法加载
|
||||||
|
err = tfidf.LoadDict(idfPath)
|
||||||
|
if err != nil {
|
||||||
|
glog.Warningf(context.Background(), "加载自定义 IDF 字典失败 [%s]: %v,将使用默认字典", idfPath, err)
|
||||||
|
// 回退到默认加载方式
|
||||||
|
err = tfidf.LoadIdf()
|
||||||
|
} else {
|
||||||
|
glog.Infof(context.Background(), "成功加载自定义 IDF 字典: %s", idfPath)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 使用默认的 IDF 字典
|
||||||
|
err = tfidf.LoadIdf()
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -71,6 +90,29 @@ func newGseTool() (tool *gseTool, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getIdfDictPath 获取 IDF 字典文件路径
|
||||||
|
func getIdfDictPath() string {
|
||||||
|
// 1. 尝试从容器内的默认挂载路径加载(Docker 卷映射)
|
||||||
|
containerPath := "/app/dict/zh/idf.txt"
|
||||||
|
if _, err := os.Stat(containerPath); err == nil {
|
||||||
|
return containerPath
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 尝试从当前工作目录的 dict/zh/idf.txt 加载
|
||||||
|
workDir, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
localPath := filepath.Join(workDir, "dict", "zh", "idf.txt")
|
||||||
|
if _, err := os.Stat(localPath); err == nil {
|
||||||
|
return localPath
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 如果没有找到自定义路径,返回空字符串,使用默认字典
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
// Cut 分词(关键词提取唯一正确模式:精确模式 + HMM)
|
// Cut 分词(关键词提取唯一正确模式:精确模式 + HMM)
|
||||||
func (k *gseTool) Cut(text string) []string {
|
func (k *gseTool) Cut(text string) []string {
|
||||||
return k.seg.Cut(text, true)
|
return k.seg.Cut(text, true)
|
||||||
|
|||||||
132
utils/utils.go
132
utils/utils.go
@@ -13,7 +13,7 @@ import (
|
|||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gitea.com/red-future/common/beans"
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
"github.com/gogf/gf/v2/container/gvar"
|
"github.com/gogf/gf/v2/container/gvar"
|
||||||
"github.com/gogf/gf/v2/database/gredis"
|
"github.com/gogf/gf/v2/database/gredis"
|
||||||
"github.com/gogf/gf/v2/errors/gcode"
|
"github.com/gogf/gf/v2/errors/gcode"
|
||||||
@@ -460,3 +460,133 @@ func IsLocalIP(ip string) bool {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetLocalIP 获取本机有效的局域网 IPv4 地址
|
||||||
|
func GetLocalIP() string {
|
||||||
|
addrs, err := net.InterfaceAddrs()
|
||||||
|
if err != nil {
|
||||||
|
return "127.0.0.1"
|
||||||
|
}
|
||||||
|
|
||||||
|
var validIPs []string
|
||||||
|
|
||||||
|
for _, addr := range addrs {
|
||||||
|
ipnet, ok := addr.(*net.IPNet)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
ip := ipnet.IP
|
||||||
|
|
||||||
|
if isIPValid(ip) {
|
||||||
|
validIPs = append(validIPs, ip.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 优先返回非 169.254.x.x 的 IP
|
||||||
|
for _, ip := range validIPs {
|
||||||
|
if !strings.HasPrefix(ip, "169.254.") {
|
||||||
|
return ip
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 其次返回 169.254.x.x(最后的选择)
|
||||||
|
if len(validIPs) > 0 {
|
||||||
|
return validIPs[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
return "127.0.0.1"
|
||||||
|
}
|
||||||
|
|
||||||
|
// isIPValid 判断 IP 是否有效
|
||||||
|
func isIPValid(ip net.IP) bool {
|
||||||
|
// 不是 loopback (127.0.0.1)
|
||||||
|
if ip.IsLoopback() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 是 IPv4
|
||||||
|
if ip.To4() == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 不是链路本地地址 (169.254.0.0/16)
|
||||||
|
if ip[0] == 169 && ip[1] == 254 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 不是组播地址
|
||||||
|
if ip.IsMulticast() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 不是未指定地址 (0.0.0.0)
|
||||||
|
if ip.IsUnspecified() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetServerPort(ctx context.Context) string {
|
||||||
|
address := g.Cfg().MustGet(ctx, "server.address", ":8080").String()
|
||||||
|
// address 格式如 ":3009",去掉冒号
|
||||||
|
if strings.HasPrefix(address, ":") {
|
||||||
|
return address[1:]
|
||||||
|
}
|
||||||
|
return "8080"
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetLocalAddress 获取局域网地址(IP:端口)
|
||||||
|
func GetLocalAddress(ctx context.Context) string {
|
||||||
|
ip := GetLocalIP()
|
||||||
|
port := GetServerPort(ctx)
|
||||||
|
|
||||||
|
if port == "80" || port == "443" {
|
||||||
|
return ip
|
||||||
|
}
|
||||||
|
return ip + ":" + port
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSchemaFromRequest 从当前请求中获取协议(http/https)
|
||||||
|
func GetSchemaFromRequest(ctx context.Context) string {
|
||||||
|
r := g.RequestFromCtx(ctx)
|
||||||
|
if r == nil {
|
||||||
|
return "http"
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. 代理场景:X-Forwarded-Proto
|
||||||
|
if proto := r.Header.Get("X-Forwarded-Proto"); proto != "" {
|
||||||
|
return proto
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 代理场景:X-Forwarded-Scheme
|
||||||
|
if proto := r.Header.Get("X-Forwarded-Scheme"); proto != "" {
|
||||||
|
return proto
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. TLS 连接(直接 HTTPS)
|
||||||
|
if r.TLS != nil {
|
||||||
|
return "https"
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 默认 HTTP(这行很重要!)
|
||||||
|
return "http" // ← 确保有这行
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetLocalBaseURL 获取局域网基础 URL(动态协议 + IP + 端口)
|
||||||
|
func GetLocalBaseURL(ctx context.Context) string {
|
||||||
|
schema := GetSchemaFromRequest(ctx)
|
||||||
|
addr := GetLocalAddress(ctx)
|
||||||
|
return schema + "://" + addr
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCallbackURL 获取回调地址(完整 URL)
|
||||||
|
func GetCallbackURL(ctx context.Context, path string) string {
|
||||||
|
baseURL := GetLocalBaseURL(ctx)
|
||||||
|
// 确保 path 以 / 开头
|
||||||
|
if !strings.HasPrefix(path, "/") {
|
||||||
|
path = "/" + path
|
||||||
|
}
|
||||||
|
return baseURL + path
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user