根本原因是RSS命名空间未显式声明导致xml.Unmarshal忽略子元素,需在结构体字段中用完整URL映射如xml:”http://purl.org/dc/elements/1.1/ creator”,并手动处理重定向、gzip解压、并发安全及缓存格式选择。

用 encoding/xml 解析 RSS 2.0 时字段经常为空?
根本原因不是 XML 结构复杂,而是 RSS 常见命名空间(如 xmlns:dc="http://purl.org/dc/elements/1.1/")和混用前缀导致 xml.Unmarshal 默认忽略子元素。go 的标准库不自动处理命名空间,也不会“猜”你想要哪个 title —— 是 channel 的还是 item 的?
- 显式声明结构体字段的 XML 标签,尤其注意嵌套层级:
XMLName xml.Name `xml:"rss"`、Title String `xml:"channel>title"` - 对带命名空间的字段(如
dc:creator),直接按带冒号的完整名映射:Creator string `xml:"http://purl.org/dc/elements/1.1/ creator"`(注意 URL 必须写全,不能省略协议) - 避免用
any或Interface{}接收未知结构 —— 它会让解析静默失败,字段全为空字符串
net/http 抓 RSS 源时遇到重定向或 gzip 崩溃?
RSS 源常返回 301/302 重定向(比如从 HTTP 跳 https),而 Go 默认的 http.DefaultClient 会自动跟随,但某些 RSS 生成器在重定向后没设好 Content-Type,导致后续解析误判编码;另外不少服务默认启用 gzip,但 xml.Unmarshal 不会自动解压。
- 手动控制重定向:设置
Client.CheckRedirect返回http.ErrUseLastResponse,自己读取resp.Header.Get("location")再发请求,确保最终响应头含Content-Type: application/rss+xml - 强制解 gzip:检查
resp.Header.Get("Content-Encoding") == "gzip",用gzip.NewReader(resp.Body)包一层再传给xml.NewDecoder - 别依赖
resp.Body直接传给xml.Decode—— 万一 Body 已被读过(比如打印了 raw body 调试),就会得到空数据
并发拉取多个 RSS 源时 panic: “invalid memory address”?
典型表现是跑几轮后在 xml.Unmarshal 或 http.Do 处 panic,实际是共享了未加锁的结构体字段(比如共用一个 *http.Client 或全局切片),或在 goroutine 里直接修改了 map / slice 而没同步。
- 每个 goroutine 应该有自己的局部变量接收解析结果,不要往同一个
[]Item里 append —— 改用sync.WaitGroup+ 闭包捕获,或收集到 channel 后统一合并 -
http.Client本身是并发安全的,但它的Transport如果被手动替换(比如加了自定义DialContext),就得确认底层连接池没被多 goroutine 错误复用 - XML 解析过程不涉及共享状态,但如果你在
Unmarshal后立刻修改结构体指针字段(比如补全item.URL = feedURL),要确保该结构体没被其他 goroutine 同时读取
本地缓存 RSS 数据该用什么格式?别碰 json
JSON 看似方便,但 RSS 的 pubDate 格式不统一(RFC 822、RFC 850、ISO 8601 都有),Go 的 time.Time 反序列化 JSON 时容易出错;更麻烦的是,JSON 无法保留原始 XML 的命名空间信息和属性(比如 <item dc:creator="A">),下次重新聚合时元数据就丢了。
立即学习“go语言免费学习笔记(深入)”;
- 缓存首选二进制格式:用
gob编码原生 Go 结构体,天然支持time.Time和嵌套指针,且体积小、速度快 - 如果必须人眼可读,选 XML 本身 —— 把解析后的结构体用
xml.Marshal写回文件,下次直接xml.Unmarshal,零信息损失 - 绝对避免把
map[string]interface{}存 JSON:字段类型在反序列化时丢失,pubDate变成 string,排序、过滤全得手动 parse
真正卡住人的从来不是怎么解析 XML,而是 RSS 源本身质量参差——有的连 </item> 都漏写,有的在 description 里塞未转义 HTML。建议在 Unmarshal 后加一层校验:检查必要字段非空、日期能 parse 成 time.Time、link 字段是合法 URL。这些细节不提前挡掉,后面聚合逻辑越写越像修仙。