用 Go + Next.js 搭一套可上线的个人博客

Article

用 Go + Next.js 搭一套可上线的个人博客

管理员技术分享165 阅读

用 Go + Next.js 搭一套可上线的个人博客

个人博客看起来只是「写文章、发评论」,真正要长期可维护,你会发现它同时覆盖了内容系统、鉴权、文件上传、反代、HTTPS 与部署流水线。很多项目死在第一周的漂亮 UI 上,却没把读写链路和上线路径做稳。这篇文章按一套真实可上线的拆分方式,讲清楚为什么拆、怎么拆、以及每一层要对齐什么。目标不是堆概念,而是让你拿到一张可执行的蓝图:公开站怎么读、后台怎么写、流量怎么进机器、改完配置为什么还要重建前端。

为什么选择 Go API + Next.js

前后端拆开,不是为了炫技,而是为了把两类问题隔离开。

后端更适合处理边界清晰的业务:文章 CRUD、评论审核、JWT 登录、上传校验。用 Gin + GORM + MySQL,能把接口契约写死,部署物体积小,健康检查简单。出问题时,你也可以单独滚动后端而不动前端构建。Go 的编译型产物对小机器也很友好:内存占用可控,冷启动快,适合放在同一台已经跑着别的站点的云主机上。

前端更适合处理展示与交互:首页列表、详情页 SEO、后台表单、Markdown 渲染。Next.js App Router 可以在服务端拉公开数据做首屏渲染,对博客这种偏读站点很友好;后台管理又能用同一仓库的 React 页面完成,不必再开一个 Vite 管理端。把前台与后台放在同一前端工程里,路由上隔离、构建上共享组件,长期改样式时不会出现「两个项目两套设计 token」的割裂。

更关键的一点是同源反代。浏览器只访问域名根路径与 /api/uploads,不要把 NEXT_PUBLIC_API_URL 指到公网某个 :8080。同源之后,CORS、Cookie、混合内容问题都会少一半。备案域名前用 IP、之后切域名,也只是改 Nginx 与构建参数,而不是改业务代码。很多人一开始图省事让前端直接打后端端口,等上了 HTTPS 才发现证书、跨域、混合内容一起炸,返工成本远高于第一天把反代写对。

模块边界怎么切

内容层只保留真正会变的数据:

  • 文章:标题、slug、摘要、Markdown 正文、状态(草稿/发布)、置顶、发布时间
  • 分类 / 标签:前台筛选与归档;文章与标签是多对多
  • 评论:前台可写,后台审核(待审/通过/拒绝)
  • 友链:简单列表即可,不必过度设计

slug 是对外稳定标识,比自增 ID 更适合做 URL。发布后尽量别改;非改不可时,至少在网关或应用层保留旧 slug 的重定向,否则外链、搜索引擎收录和你自己的分享链接会一起失效。草稿与已发布要用明确状态机,不要靠「标题前面加一个草稿二字」这种口头约定。

鉴权层只服务后台。公开读接口无 Token;写接口一律走 /api/admin/*,中间件校验签名、过期时间与 role=admin。博客流量小,但「默认拒绝、显式放行」的习惯要从第一天养成。不要把 JWT 当作可随意丢到 localStorage 再传到所有接口的万能钥匙——后台页面同源携带 Bearer 已经够用。公开评论提交可以单独限流,但仍属于写路径,要对内容长度、链接密度、提交频率做服务端校验,不能只信前端表单。

存储层建议一开始就明确:

  • MySQL 存结构化内容
  • 本地磁盘或对象存储存上传文件;Nginx 负责把 /uploads 反代出去
  • 配置与密钥放环境变量,绝不进仓库

上传目录要进入备份清单。很多人只备份数据库,结果文章还在、封面全丢,站点观感会直接崩掉。对象存储更稳,但个人站用本机磁盘 + 定期打包也完全够用,关键是备份脚本真的会跑、并且你恢复演练过至少一次。

接口与内容格式

正文存 Markdown,而不是后端渲染好的 HTML。好处是排版权在前端、XSS 面更可控,写作体验也更接近日常笔记。详情页用 react-markdown 一类库渲染即可;代码块配合 highlight 方案,但不要一开始就上超重编辑器。编辑器越重,后台发布路径越脆弱;先保证「粘贴 Markdown → 预览 → 发布」闭环稳定,再谈所见即所得。

列表接口要为「首页 / 分类 / 标签 / 搜索」准备同一套分页与过滤参数,避免每个入口写一套 SQL。公开列表只返回已发布内容;后台列表可按状态筛选。分页要带稳定排序字段(例如 published_at DESC, id DESC),否则在高频写入时会出现翻页重复或跳过。搜索如果只是标题/摘要 LIKE,要接受它的能力上限;真要全文体验,再引入独立搜索,而不是把 MySQL 拖去当搜索引擎硬撑。

上传接口必须做类型与大小限制。封面图常见踩坑是:后端放行了,Nginx client_max_body_size 还是默认 1m,表现为前台「上传失败但原因不明」。排障时先看网关再看应用。另一个隐性问题是 URL 拼接:数据库存相对路径 /uploads/xxx.png,前端要用站点同源前缀拼出来;如果错误地拼成后端容器内网地址,页面上就会出现裂图。

读模型与写模型不必完全一样

公开详情页需要的是「可读的文章 + 标签 + 分类」;后台编辑页需要的是「可改的全部字段 + 草稿状态」。用同一接口硬凑两边需求,最终要么前台多返回敏感字段,要么后台少字段来回补请求。更干净的做法是公开 API 与 admin API 分包:公开接口做裁剪与缓存友好;admin 接口保证完整与准确。评论也同理——前台只看已通过;后台看全部状态并支持批量审核。

缓存可以后置。先保证数据库查询形状正确(列表不拉正文、关联预加载),再决定是否给首页加短 TTL 缓存。流量很小的博客,错误缓存失效策略带来的「改了不生效」投诉,往往比几毫秒延迟更伤体验。

部署形态:容器负责应用,宿主机负责入口

同机如果已有 Nginx 或其他站点,业务容器只应监听 127.0.0.1。前端例如 13000,后端 18080。Docker Compose 用健康检查串起依赖:MySQL ready → 后端 ready → 前端启动。健康检查不要只看进程是否存在,最好打到 /health 或真实首页路径。发布失败时,卡在哪一层 healthy,就去哪一层看日志,比「全部 restart 碰运气」高效得多。

宿主机 Nginx 做三件事:TLS、按域名分流、把路径转到本机端口。证书可以用商业证书,也可以 Let's Encrypt;www 与裸域都解析时,证书 SAN 必须都覆盖,否则用户会在某个入口看到证书警告。HTTP 统一 301 到 HTTPS,并用 $host 保持主机名,避免把所有人硬跳到单一规范域名——除非你明确要做规范化。

代码同步与密钥不同步。rsync 可以推代码;.env.prod、证书、上传目录应留在服务器。前端构建参数里的 SITE_PROTOCOLDOMAIN 决定运行时拼出来的绝对地址,切 HTTPS 后要重建前端镜像,否则页面里仍可能残留 http:// 资源地址。这也是为什么「只 reload Nginx」常常不够:网关已经是 HTTPS,前端产物还活在旧协议假设里。

上线检查清单

  1. 公开首页、详情、归档能打开,且无跨域报错
  2. 后台登录、发文、上传封面、审核评论闭环可用
  3. nginx -t 通过,证书链完整,HTTP 强制跳 HTTPS
  4. 容器重启后数据仍在(数据卷没丢)
  5. 备份策略至少覆盖 MySQL 与上传目录
  6. 用手机网络或无痕窗口再测一遍,避免你本机 DNS / Hosts 造成的假象

小结

博客项目的价值不在主题皮肤,而在「能持续写、能安全发、能稳定上、能在一年后还敢改」。Go 负责稳的边界,Next.js 负责读的体验,Nginx 负责把公网流量接到正确进程。把这三层对齐后,后面加统计、加评论审核规则、加更多站点,都只是在清晰边界上叠加,而不是在一团浆糊里打补丁。先追求可上线的完整链路,再追求好看;顺序反了,大多数个人项目会停在半成品演示站。

评论

暂无评论,来聊聊这篇文章吧。