Files
dygou_go/utils.go
T
2026-06-19 11:30:19 +08:00

136 lines
3.4 KiB
Go

package main
import (
"encoding/json"
"fmt"
"net/http"
"strconv"
"strings"
"time"
)
// readJSON 读取请求 JSON。
func readJSON(r *http.Request, out any) error {
defer r.Body.Close()
return json.NewDecoder(r.Body).Decode(out)
}
// writeJSON 写出 JSON 响应。
func writeJSON(w http.ResponseWriter, value any) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
_ = json.NewEncoder(w).Encode(value)
}
// writeError 写出统一错误 JSON,同时设置 HTTP 状态码。
func writeError(w http.ResponseWriter, status int, err error) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(status)
_ = json.NewEncoder(w).Encode(map[string]any{
"success": false,
"error": err.Error(),
})
}
// appendCacheBuster 给 URL 追加时间戳,避免时间接口被缓存。
func appendCacheBuster(rawURL string) string {
sep := "?"
if strings.Contains(rawURL, "?") {
sep = "&"
}
return rawURL + sep + "_=" + strconv.FormatInt(time.Now().UnixNano(), 10)
}
// cloneStringMap 复制 map,避免异步任务读到调用方后续修改。
func cloneStringMap(in map[string]string) map[string]string {
out := make(map[string]string, len(in))
for k, v := range in {
out[k] = v
}
return out
}
// mergeCookie 把指定 Cookie 写入原 Cookie 字符串,已有同名 Cookie 会被覆盖。
func mergeCookie(cookie, name, value string) string {
parts := strings.Split(cookie, ";")
pairs := make([]string, 0, len(parts)+1)
replaced := false
for _, part := range parts {
part = strings.TrimSpace(part)
if part == "" {
continue
}
key, _, ok := strings.Cut(part, "=")
if ok && strings.TrimSpace(key) == name {
pairs = append(pairs, name+"="+value)
replaced = true
continue
}
pairs = append(pairs, part)
}
if !replaced && value != "" {
pairs = append(pairs, name+"="+value)
}
return strings.Join(pairs, "; ")
}
// trimForLog 截断接口响应,避免日志刷屏。
func trimForLog(s string, max int) string {
s = strings.TrimSpace(s)
if len(s) <= max {
return s
}
return s[:max] + "..."
}
// emptyDefault 在字符串为空时返回默认值。
func emptyDefault(value, fallback string) string {
if strings.TrimSpace(value) == "" {
return fallback
}
return value
}
// safeFilename 替换文件名中的危险字符。
func safeFilename(name string) string {
replacer := strings.NewReplacer("/", "_", "\\", "_", ":", "_", "*", "_", "?", "_", "\"", "_", "<", "_", ">", "_", "|", "_")
return replacer.Replace(name)
}
// maskCookie 返回 Cookie 摘要,避免把完整凭据暴露给前端。
func maskCookie(cookie string) string {
pairs := strings.Split(cookie, ";")
masked := make([]string, 0, 3)
total := 0
for _, pair := range pairs {
key, value, ok := strings.Cut(strings.TrimSpace(pair), "=")
if !ok || key == "" {
continue
}
total++
if len(masked) >= 3 {
continue
}
masked = append(masked, key+"="+maskValue(value))
}
if total == 0 {
return ""
}
if total > len(masked) {
masked = append(masked, fmt.Sprintf("...共%d项", total))
}
return strings.Join(masked, "; ")
}
// maskValue 保留少量首尾字符用于识别,其余替换为星号。
func maskValue(value string) string {
value = strings.TrimSpace(value)
if value == "" {
return "****"
}
runes := []rune(value)
if len(runes) <= 8 {
return "****"
}
return string(runes[:4]) + "****" + string(runes[len(runes)-4:])
}