- 新增访问统计:visitstats 服务与查询、visit_capture 中间件、爬虫/来源识别、管理端 analytics 页面 - 新增侧边栏:sidebar 服务与 handler、管理端 sidebar 配置页、前端侧边栏组件 - 新增 widget 嵌入代码生成(widgetCode)与 widgetApi - 遥测逻辑迁移至 handler 层,删除 service/telemetry - env 示例补充 Docker 部署可信代理 IP 说明
64 lines
1.9 KiB
Go
64 lines
1.9 KiB
Go
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
|
||
}
|