Golang Bud框架实现feedparser RSS解析客户端运行报错求助
问题背景
- 试用Bud全栈框架实现简易RSS解析器,目标是每次请求时拉取对应RSS源数据返回页面
- 参考框架作者的官方教程开发,修改了教程中拉取HackerNews JSON数据的客户端代码,代码可正常编译,但运行时抛出如下错误:
conjure: generate "bud/.app/controller/controller.go" > controller: unable to load definition for field Extensions in stories > parser: unable to find declaration for "Extensions" in "ext" |
- 已尝试修改返回对象名、创建gofeed.Feed结构体指针等方案,均未解决问题,初步怀疑和gofeed解析器的使用方式有关,需要排查方向指引。
关联代码
feedparser/client.go
// Package feedparser is a simple RSS reader client that leverages gofeed package feedparser import ( "context" "fmt" "github.com/mmcdole/gofeed" ) const baseURL = `https://ec.europa.eu/info/news/feed_en` // Feed Client, it uses gofeed parser to open a connection with the rss/atom/json data feed func New() *Client { feedParser := gofeed.NewParser() return &Client{feedParser} } // Feed Client type Client struct { *gofeed.Parser } // FrontPage gets the feeds and prints them as a list func (c *Client) FrontPage(ctx context.Context) (*gofeed.Feed, error) { feedData := `<rss version="2.0"> <channel> <webMaster>example@site.com (Example Name)</webMaster> </channel> </rss>` fd, err := c.RSSTranslator.Translate(feedData) if err != nil { return fd, err } fmt.Println(fd) return fd, nil }
controller/controller.go
package controller import ( context "context" "github.com/AlessioNar/eunews/feedparser" "github.com/mmcdole/gofeed" ) type Controller struct { // Dependencies... FP *feedparser.Client } // Index of stories // GET / func (c *Controller) Index(ctx context.Context) (stories *gofeed.Feed, err error) { return c.FP.FrontPage(ctx) }
根因分析
核心问题出在Bud框架自带的代码生成工具conjure的解析限制:
conjure在生成控制器路由绑定代码时,会递归遍历控制器方法返回值的所有字段类型,完成类型校验和模板渲染。你直接返回第三方库gofeed的*gofeed.Feed结构体,这个结构体内嵌了来自ext子包的Extensions字段,类型为map[string][]ext.Extension,conjure无法递归解析到你项目外部依赖包中没有在本地显式声明的类型定义,就会抛出找不到Extensions声明的错误。
原教程中返回的是项目内自定义的结构体,所有字段都是基础类型或者项目内声明的类型,不会触发这个解析限制。
另外你现有代码还有一个隐藏bug:c.RSSTranslator.Translate方法的入参要求是io.Reader类型,直接传入字符串会触发类型错误,哪怕解决了代码生成问题,运行时也会报错。
修复方案
不要直接在控制器层返回第三方依赖的结构体,在项目内自定义需要的返回结构体,在client层完成第三方结构到本地结构的转换后再返回:
- 在feedparser包内定义本地结构体,只保留页面渲染需要的字段,全部使用conjure可识别的基础类型/本地类型:
// Feed 首页返回的RSS源整体结构 type Feed struct { Title string Description string Link string Items []FeedItem } // FeedItem 单条RSS内容结构 type FeedItem struct { Title string Link string Published string Summary string }
- 修改
FrontPage方法的返回值为自定义的*Feed类型,修正RSS解析逻辑,完成结构转换:
func (c *Client) FrontPage(ctx context.Context) (*Feed, error) { feedData := `<rss version="2.0"> <channel> <webMaster>example@site.com (Example Name)</webMaster> </channel> </rss>` // 修正原有的错误调用,使用gofeed提供的ParseString方法解析字符串内容 // 如果要直接拉取线上RSS地址,可直接调用c.ParseURL(baseURL) rawFeed, err := c.ParseString(feedData) if err != nil { return nil, err } // 转换为本地自定义结构 res := &Feed{ Title: rawFeed.Title, Description: rawFeed.Description, Link: rawFeed.Link, } for _, item := range rawFeed.Items { res.Items = append(res.Items, FeedItem{ Title: item.Title, Link: item.Link, Published: item.Published, Summary: item.Description, }) } return res, nil }
- 同步修改controller层Index方法的返回值类型为
*feedparser.Feed,移除controller层对gofeed包的直接依赖即可。
内容的提问来源于stack exchange,提问作者anardin
相关产品推荐
相关产品推荐

