package utils import ( "path" "path/filepath" "strconv" "strings" "github.com/PuerkitoBio/purell" ) // PathSegment 路由路径段:有 slug 用 slug,否则回退为数字 id。 func PathSegment(slug string, id int64) string { if s := strings.TrimSpace(slug); s != "" { return s } if id > 0 { return strconv.FormatInt(id, 10) } return "" } // PathInfo 路径信息 type PathInfo struct { Dir string // 目录 Ext string // 扩展名 Filename string // 没有扩展名的文件名名称 FullFileName string // 文件全名 } // PathForInfo 解析路径 // 返回文件,路径,文件名等信息 func PathForInfo(path string) (pi PathInfo) { if path == "" { return } ext := filepath.Ext(path) dir, name := filepath.Split(path) pi.Dir = dir pi.Ext = ext pi.Filename = strings.TrimRight(name, ext) pi.FullFileName = name return } // JoinUrlPath 域名与uri拼接(走 purell 标准化,会剥掉尾部斜杠)。 // 适用于 CDN 文件链接(m3u8 分段、vtt、静态图等)这类"不需要尾部斜杠"的场景。 // 需要保留尾部斜杠的页面 URL(sitemap/rss/indexnow)请使用 JoinUrlPathKeepSlash。 func JoinUrlPath(host string, uri string) (urlpath string) { urlpath = joinRawUrlPath(host, uri) if urlpath == "" { return } // 标准化 URL normalized, err := purell.NormalizeURLString(urlpath, purell.FlagsUsuallySafeGreedy) if err != nil { return urlpath } return normalized } // JoinUrlPathKeepSlash 域名与uri拼接,保留 uri 原始的尾部斜杠,不做任何标准化。 // sitemap/rss/indexnow 的页面 URL 必须与路由注册的 /archives/:id/ 等完全一致, // 否则爬虫每次访问都会被 gin 的 RedirectTrailingSlash 301 到带 / 的地址, // 浪费抓取预算并造成重定向链。 func JoinUrlPathKeepSlash(host string, uri string) string { return joinRawUrlPath(host, uri) } // joinRawUrlPath 纯拼接,不做任何标准化。 func joinRawUrlPath(host string, uri string) (urlpath string) { if uri == "" { return } switch { case strings.HasSuffix(host, "/") && strings.HasPrefix(uri, "/"): urlpath = host[0:len(host)-1] + uri case !strings.HasSuffix(host, "/") && !strings.HasPrefix(uri, "/"): urlpath = host + "/" + uri default: urlpath = host + uri } return } func JoinUrlPathV2(host string, uri string) string { return path.Join(host, uri) }