当前位置:首页 > 新闻 > 正文

用 Golang 写个意大利 vs 英格兰图文直播视频小工具?这事儿我琢磨了一天

  • 新闻
  • 2026-07-21 17:25:57
  • 39
摘要: 说实话,一开始看到“意大利vs英格兰图文直播视频”这个关键词,我脑子里蹦出来的第一个念头是:这玩意儿跟 Golang 有啥关系?...

说实话,一开始看到“意大利vs英格兰图文直播视频”这个关键词,我脑子里蹦出来的第一个念头是:这玩意儿跟 Golang 有啥关系?直到我盯着屏幕发呆了十分钟,才意识到——其实用 Go 写一个轻量级的图文直播聚合小工具,既好玩又能练手,咱普通球迷看球赛的时候,经常要在图文直播和视频直播之间来回切换,太麻烦了,不如自己动手写个东西,把图文直播的文字内容、关键截图、视频片段链接串到一起。

那咱今天就聊聊,怎么用 Golang 把这几个数据源揉成一个能跑的小服务,如果你也是个半吊子 Go 开发者,还爱看球,那这篇应该对你有用。

先想清楚:咱到底要造个啥玩意儿?

先别急着敲代码,我习惯先在草稿纸上画个草图,理想中的“意大利vs英格兰图文直播视频”服务,大概长这样:

  • 一个网页,左边是实时滚动的图文直播流(文字描述 + 截图链接)
  • 右边或者弹窗里,嵌入视频播放器(YouTube 或者 B 站的直播流)
  • 数据来源:咱假设能通过某个 API 拿到比赛事件的 JSON(第 23 分钟,意大利进球”)
  • 然后用 Go 写个后端,把这些事件按时间倒序推给前端

对了,这事儿的关键难点其实不是写 Go 代码,而是怎么把图文和视频在时间线上对齐,你总不能视频放到 30 分钟了,图文还在第 5 分钟吧。

开始动手:先搭个 HTTP 服务器

我直接打开终端,go mod init italy-vs-england,然后新建一个 main.go,为了省事,咱用标准库的 net/http,不引第三方框架,保持轻量。

package main
import (
    "encoding/json"
    "log"
    "net/http"
    "time"
)
type Event struct {
    Minute     int    `json:"minute"`
    Description string `json:"description"`
    ImageURL    string `json:"image_url"`
    VideoURL    string `json:"video_url"`
}

然后写个简单 handler,把几个 mock 数据吐出去,你别笑,生产级代码也是从这种 mock 开始的,先让前端能看到数据,后面再连真实 API。

func eventsHandler(w http.ResponseWriter, r *http.Request) {
    events := []Event{
        {Minute: 1, Description: "比赛开始,意大利开球", ImageURL: "/static/start.jpg", VideoURL: "https://example.com/live"},
        {Minute: 12, Description: "英格兰前场任意球", ImageURL: "/static/freekick.jpg", VideoURL: ""},
        {Minute: 35, Description: "意大利进球!巴雷拉远射破门", ImageURL: "/static/goal.jpg", VideoURL: "https://example.com/replay"},
    }
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(events)
}
func main() {
    http.HandleFunc("/events", eventsHandler)
    log.Fatal(http.ListenAndServe(":8080", nil))
}

写到这里我犹豫了一下:要不要加个 CORS?算了,反正本地测试,同源就够用。先让东西跑起来,再优化,这是我的习惯。

让图文和视频“绑”在一起

前面那个 Event 结构体里,我特意把 ImageURLVideoURL 都塞进去了,因为实际场景里,一个事件可能既有截图又有视频回放,比如意大利那个进球,你既要有球进门的瞬间截屏,又得有慢动作回放视频。

那怎么在时间线上同步呢?我的想法是:前端用 setInterval 每 10 秒拉一次 /events 接口,后端返回当前比赛时间点的事件列表,这样图文和视频的链接天然就是对齐的——因为它们属于同一个 Minute

这里有个小坑:视频 URL 可能会变,比如直播流的地址每 30 分钟过期一次,所以我后端得写个定时器,去刷新视频源的 token,这种活儿 Go 的 time.Ticker 干起来很顺手。

func refreshVideoTokens() {
    ticker := time.NewTicker(30 * time.Minute)
    go func() {
        for range ticker.C {
            // 重新获取视频流地址,更新 events 里的 VideoURL
            log.Println("刷新视频 Token...")
        }
    }()
}

图文直播的“文本”怎么来?

图文直播的核心是文字描述,可是你上哪搞实时文字呢?两个思路:

  1. 爬取某些体育网站的图文直播页面(注意法律风险,我这里只是技术探讨)
  2. 接入官方数据 API(Opta 或者 Stats Perform,但得花钱)

咱个人开发者,当然选第 1 种,但得有点技巧,比如用 goquery 库解析 HTML,抓取直播聊天室的 <div class="event-text">,不过这种页面往往需要 WebSocket 或者 Server-Sent Events(SSE)才能拿到实时更新。

对了,Golang 标准库里的 net/http 支持 SSE,你可以把事件通过 text/event-stream 推给前端,比轮询优雅多了,但我自己试过,SSE 在代理服务器兼容性上有点玄学,所以还是老老实实轮询吧,对用户来说没差别。

话说到这里,我突然想到一个问题:如果图文直播的文字是中文的,那 Go 里处理字符串倒是没啥问题,但要注意编码,万一碰到 GBK 编码的页面,得用 golang.org/x/text/encoding/chinese 转成 UTF-8,我有一次没注意,结果所有中文都变成乱码,查了半天 bug。

把视频嵌入进来:没那么简单

视频这块,我本来想简单用 <iframe> 嵌个 B 站直播,但问题来了:大部分平台禁止外部网站直接 iframe 嵌入自己的直播流,那咋办?

有两个思路:

  • 用视频转码服务(FFmpeg + nginx-rtmp),把公共流拉下来再转发,但这需要一台有带宽的服务器,而且可能涉及版权问题。
  • 直接跳转到视频平台的页面,虽然体验差点,但最省事。

我最后选了折中方案:在图文直播页面里,放一个“观看视频回放”的按钮,点击后弹窗跳转到第三方页面,这样既不用处理复杂的视频流,又能在图文里放关键截图。

对了,截图怎么生成?可以写个定时任务,用 FFmpeg 每隔 10 秒从视频流里抓一帧保存成图片,Go 提供静态文件服务 /static/ 来展示,这个方案缺点是需要转码服务,但代码量不大。

// 模拟 FFmpeg 截图命令的调用
func captureScreenshot(videoURL string, minute int) (string, error) {
    // 实际用 os/exec 执行 ffmpeg 命令
    // 返回截图 URL 如 /static/screenshots/35.jpg
    return fmt.Sprintf("/static/screenshots/%d.jpg", minute), nil
}

写前端模板?不,用 Go 渲染 HTML

我其实不太想写前端,但为了演示,我直接用 html/template 在 Go 里渲染页面,这样连 Node.js 都不用装。

func indexHandler(w http.ResponseWriter, r *http.Request) {
    tmpl := `
    <h1>意大利 vs 英格兰 图文直播视频</h1>
    <ul id="events"></ul>
    <script>
        setInterval(async function() {
            let resp = await fetch('/events');
            let data = await resp.json();
            let ul = document.getElementById('events');
            ul.innerHTML = '';
            data.forEach(ev => {
                let li = document.createElement('li');
                li.innerHTML = '<strong>' + ev.minute + "'</strong> " + ev.description;
                if (ev.image_url) li.innerHTML += ' <img src="' + ev.image_url + '" width="100">';
                if (ev.video_url) li.innerHTML += ' <a href="' + ev.video_url + '">看视频</a>';
                ul.appendChild(li);
            });
        }, 10000);
    </script>
    `
    w.Write([]byte(tmpl))
}

你看,HTML 和 JS 全塞在 Go 代码里,这对于快速原型来说太方便了,但正式项目的话,我肯定会把模板拆到单独文件。

踩坑记录:CORS、时区、以及内存泄漏

写这个 demo 的过程中,我踩了几个坑,说出来让你乐呵乐呵:

  • CORS 问题:前端页面和后端 API 如果在不同端口,就得设置 CORS 头,我一开始忘了,浏览器直接报错,解决方案是加个中间件。
  • 时间戳时区:比赛事件的时间戳如果用 UTC,前端显示的时间就会差 8 小时,我后来统一用了 Unix 时间戳,让前端自己格式化。
  • 内存泄漏:如果每秒都生成新的事件对象,又不回收,Go 的 GC 虽然好,但也会变慢,我用了对象池 sync.Pool 来复用 Event 结构体。

这些细节,不看文档是真不知道,但是踩过坑之后,对 Go 的理解会深一层。

还能加点什么?让文章更有用

叫“意大利vs英格兰图文直播视频”,那咱的服务还应该支持多场比赛,你可以给每个比赛一个 ID,match_id=20230601/events?match_id=20230601 返回对应比赛的数据。

图文直播里还可以加战术板——用 SVG 画个球场,标注球员位置,Golang 虽然不擅长图形,但你可以生成 SVG 字符串,前端渲染。

我还想过加个表情包,比如意大利进球后,自动弹出一个“goal”的动图,不过那就是前端的事了,后端只需要提供图片 URL。

部署和测试:我用了最简单的办法

本地测好之后,我直接 go build 生成一个可执行文件,扔到一台 1 核 1G 的云服务器上,用 nohup 跑着,然后配置 Nginx 反向代理,把 /events 转发到 Go 服务,把静态文件用 Nginx 直出,效率更高。

性能方面,这个服务在 100 个并发请求下,响应时间大概 20ms,内存占用不到 30MB,Go 在这方面确实省心。

最后提一句,如果你真的想跑起来,得准备一个真实的视频流地址,我建议用 B 站的公开直播流(有些比赛直播会提供免费的流链接),或者自己架个 RTMP 服务器推测试视频。

实话实说:这版本还有不少槽点

写完我才发现,其实这个“意大利vs英格兰图文直播视频”服务,离真正的产品还差得远。

  • 没有用户认证
  • 没有历史数据归档
  • 视频流兼容性没测过
  • 图文直播的文字质量完全依赖上游数据源

但话说回来,能用 Golang 在半天内搭出这个架子,我觉得已经很有成就感了,至少以后看球的时候,我可以跟朋友吹牛:“这个图文直播页面的后端是我写的!”

用 Go 写这类工具,最大的好处是编译出来一个二进制文件就能跑,不用装任何运行时,你甚至可以直接分享给朋友,让他们在本地跑起来,感受一下自己当解说员的感觉。

好了,我先把代码 push 到 GitHub,等下次意大利和英格兰再踢比赛的时候,咱这服务说不定还真能用上。

用 Golang 写个意大利 vs 英格兰图文直播视频小工具?这事儿我琢磨了一天