go 的 http.redirect 跳转后 url 没变或报 302,因默认用 http.statusfound(302),浏览器缓存跳转且不更新地址栏历史;目标 url 必须为完整绝对地址(含 http:// 或 https://),否则静默拼接出非法路径;生产环境应优先用 http.statusmovedpermanently(301);重定向后不可再写响应体,否则 panic。

Go 的 http.Redirect 为什么跳转后 URL 没变或报 302?
因为默认用的是 http.StatusFound(302),浏览器会缓存跳转,且不改地址栏历史;如果目标 URL 带协议但没写全(比如漏了 https://),Go 会静默拼成相对路径,结果跳到 /https:/xxx 这种非法地址,返回 404 或空白页。
- 必须确保
url参数是完整绝对地址,开头含http://或https:// - 生产环境优先用
http.StatusMovedPermanently(301),避免 SEO 折损和缓存混乱 - 别在
http.Redirect后继续写响应体——它内部已调用w.WriteHeader(),再写会 panic:http: superfluous response write - 示例正确写法:
http.Redirect(w, r, "https://example.com", http.StatusMovedPermanently)
短链存储选 map[string]string 还是数据库?
本地调试可以,上线立刻崩。内存 map 没持久化、无并发安全、重启就丢数据,且无法横向扩展。
- 开发阶段用
sync.Map替代普通map,避免concurrent map writespanic - 哪怕只跑单机,也建议从第一天就用 SQLite 或 Redis:SQLite 文件小、零配置;Redis 支持 TTL 和原子计数,适合统计点击量
- 若用 Redis,键设计别直接存
short→long,加前缀防冲突,例如url:abc123 - 别把长 URL 当 key 做反查——长度不可控,Redis key 过长影响性能
生成短码时怎么避免重复和可预测?
用递增 ID 或时间戳打头的 base62 编码,容易被爬虫遍历撞库,一天扫几百万条不是问题。
- 生成逻辑必须带随机性:用
crypto/rand取字节,再映射到字母+数字字符集(62 个) - 入库前先
SELECT检查是否存在,冲突就重试(最多 3 次,否则卡住) - 短码长度建议 5–6 位:太短易撞(62⁴ ≈ 1479 万),太长传播成本高
- 别用
math/rand—— 默认种子固定,多实例启动后生成序列一模一样
HTTP 处理函数里怎么安全读取 r.URL.Path 并提取短码?
直接截字符串或正则匹配,遇到 /a/b/c 或 /abc?ref=1 就错乱;r.URL.Path 是已解码的,但查询参数还在 r.URL.RawQuery 里,混着处理会丢参或 XSS。
立即学习“go语言免费学习笔记(深入)”;
- 用
strings.TrimPrefix(r.URL.Path, "/")去掉开头斜杠,再按/分割取第一段,比正则快且可控 - 短码只取首段,后面路径(如
/abc/log)应 404,别透传给目标站 - 对短码做白名单校验:
^[a-zA-Z0-9]{5,6}$,防止路径穿越(../)或注入字符 - 重定向前用
net/url.Parse再验一次目标 URL,拒绝javascript:、data:等危险 scheme










