feat: 站点访问统计与可配置侧边栏组件
- 新增访问统计:visitstats 服务与查询、visit_capture 中间件、爬虫/来源识别、管理端 analytics 页面 - 新增侧边栏:sidebar 服务与 handler、管理端 sidebar 配置页、前端侧边栏组件 - 新增 widget 嵌入代码生成(widgetCode)与 widgetApi - 遥测逻辑迁移至 handler 层,删除 service/telemetry - env 示例补充 Docker 部署可信代理 IP 说明
This commit is contained in:
63
backend/service/visit_ref.go
Normal file
63
backend/service/visit_ref.go
Normal file
@@ -0,0 +1,63 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 来源分类常量
|
||||
const (
|
||||
RefKindDirect = "direct"
|
||||
RefKindInternal = "internal"
|
||||
RefKindSearch = "search"
|
||||
RefKindSocial = "social"
|
||||
RefKindExternal = "external"
|
||||
)
|
||||
|
||||
// searchHosts 搜索引擎域名(按「等于或以 .子域结尾」匹配)
|
||||
var searchHosts = []string{"google.com", "bing.com", "baidu.com", "sogou.com", "so.com", "sm.cn", "duckduckgo.com", "yandex.com", "yandex.ru", "yahoo.com"}
|
||||
|
||||
// socialHosts 社交/社区域名特征
|
||||
var socialHosts = []string{
|
||||
"weibo.com", "weibo.cn", "zhihu.com", "zhuanlan.zhihu.com", "twitter.com", "x.com",
|
||||
"t.me", "telegram.me", "douyin.com", "xiaohongshu.com", "bilibili.com", "b23.tv",
|
||||
"qq.com", "tieba.baidu.com", "v2ex.com", "juejin.cn", "csdn.net", "segmentfault.com",
|
||||
"github.com", "gitee.com", "reddit.com", "facebook.com", "instagram.com", "discord.com",
|
||||
}
|
||||
|
||||
// hostMatches 按「等于或以 .子域结尾」匹配 host 与域名列表
|
||||
func hostMatches(host string, list []string) bool {
|
||||
for _, d := range list {
|
||||
if host == d || strings.HasSuffix(host, "."+d) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// ClassifyReferrer 解析并归类 Referer:返回 (来源 host, 来源类别)。
|
||||
// 空 → direct;本站 → internal;搜索引擎 → search;社交 → social;其余 → external;解析失败按 direct。
|
||||
func ClassifyReferrer(raw, siteHost string) (string, string) {
|
||||
raw = strings.TrimSpace(raw)
|
||||
if raw == "" {
|
||||
return "", RefKindDirect
|
||||
}
|
||||
u, err := url.Parse(raw)
|
||||
if err != nil || u.Host == "" {
|
||||
return "", RefKindDirect
|
||||
}
|
||||
host := strings.ToLower(u.Host)
|
||||
if i := strings.LastIndex(host, ":"); i >= 0 && !strings.Contains(host, "]") {
|
||||
host = host[:i] // 去端口
|
||||
}
|
||||
if siteHost != "" && (host == siteHost || siteHost == host) {
|
||||
return host, RefKindInternal
|
||||
}
|
||||
if hostMatches(host, searchHosts) {
|
||||
return host, RefKindSearch
|
||||
}
|
||||
if hostMatches(host, socialHosts) {
|
||||
return host, RefKindSocial
|
||||
}
|
||||
return host, RefKindExternal
|
||||
}
|
||||
Reference in New Issue
Block a user