package main import ( "fmt" "github.com/gin-gonic/gin" "os" "path/filepath" "runtime" "strings" "sync" "time" ) var ( ipLogFilePath string ipLogMu sync.Mutex ) // EnsureIPLogPathInitialized 初始化IP日志文件路径。 // 作用:根据运行系统设置默认存储位置,并确保目录存在,避免写入失败。 // 优先读取环境变量 IP_LOG_FILE(例如:/www/wwwroot/centerBook/ip.txt)。 // Windows 默认:C:\Users\www\centerBook\ip.txt;Linux 默认:/www/wwwroot/centerBook/ip.txt。 func EnsureIPLogPathInitialized() { if ipLogFilePath != "" { return } if env := os.Getenv("IP_LOG_FILE"); env != "" { ipLogFilePath = env } else { if runtime.GOOS == "windows" { ipLogFilePath = `C:\Users\www\centerBook\ip.txt` } else { ipLogFilePath = "/www/wwwroot/centerBook/ip.txt" } } dir := filepath.Dir(ipLogFilePath) _ = os.MkdirAll(dir, 0755) } // LogLargePerPage 记录超大 per_page 请求的IP信息到文本文件。 // 触发条件:当 per_page 被裁剪(原始值大于上限)时调用。 // 记录内容:时间、IP、方法、原始per_page、裁剪后per_page、路径、UA。 func LogLargePerPage(c *gin.Context, originalPerPage, sanitizedPerPage int) { EnsureIPLogPathInitialized() line := fmt.Sprintf( "%s | ip=%s | method=%s | per_page=%d->%d | path=%s | ua=%s\n", time.Now().Format("2006-01-02 15:04:05"), c.ClientIP(), c.Request.Method, originalPerPage, sanitizedPerPage, c.Request.RequestURI, strings.ReplaceAll(c.GetHeader("User-Agent"), "\n", " "), ) ipLogMu.Lock() defer ipLogMu.Unlock() f, err := os.OpenFile(ipLogFilePath, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644) if err != nil { // 静默失败,避免影响主流程 return } defer f.Close() _, _ = f.WriteString(line) } // IPLogHandler 返回 ip.txt 的内容(text/plain)。 // 用途:通过路由暴露 ip.txt,便于反向代理将 https://book.center.buzhiyushu.cn/ip.txt 映射到此接口。 func IPLogHandler() gin.HandlerFunc { return func(c *gin.Context) { EnsureIPLogPathInitialized() data, err := os.ReadFile(ipLogFilePath) if err != nil { c.String(200, "") return } c.Header("Content-Type", "text/plain; charset=utf-8") c.String(200, string(data)) } }