一、为什么又要折腾一次
时光荏苒,一晃2年半过去了,我的博客停更了这么长时间。前几天摸鱼群的几个小伙子们在比划谁的更新时间更近,并且十年之约还给我发了个邮件确认我是否还在更新。最近公司业务上很多小问题已经让AI在写了,但是我还没有让AI从头到尾完整做一个项目。借着这个机会,我想试试看我的个人博客能不能直接让AI完成。在此之前,我让AI先完整的做了一个待办事项和定投基金记账的个人软件。完美出乎我的意料,再加上我的博客是早年自己写的程序,于是我放心大胆的开始了这次更改版。
既然是自己一行行敲的,为什么不继续修修补补?原因很现实:
- 前台是服务端模板拼 HTML,用的bootstrap的pannel,没有美工,能看但是不好看;
- 后台能用,但丑。因为不是前后端分离的,所以改功能意味着要改页面;
- 手机上看老站,属于能跑,但是兼容性很差;
- 一个人维护全站,成本大头从来不在写代码,而在把自己逼成全栈开发。
所以我给自己排了八个晚上的档期。白天上班,晚上十点前后开工,领导早就习惯了我对着屏幕傻笑或者骂街的样子。
二、我下的第一道指令
10月11日21:22,我贴了一份九条的需求书:改版重做、内容数据保留;技术栈 Nginx + Vue3 + PHP + MySQL;框架用 ThinkPHP 8.1 构建 API、EleAdminPlus 做后台,前台 Vue 开发但要渲染成 HTML 方便搜索引擎抓取;LOGO 和 slogan 保留内容、重新设计形式;栏目收成首页、码海拾贝(并掉原来的程序语言/前端脚本/建站优化/系统运维)、岁月如歌;印象笔记和资源分享两个栏目不要了。
九分钟后,第一版首页出来了。
整体风格不是很好,不太喜欢这种蓝紫色,喜欢枫叶的那种风格。我桌面上有一个首页
anji66-redesign/index.html,你可以访问一下,直接复用这个首页,内页根据这个风格重新设计。
这是我给的反馈指令。这也是我这八个晚上学到的第一条:AI会非常热情地给你一套"设计感很强"的蓝紫渐变,在我看来不比当年的杀马特差到哪里去。而此前我用另一家的AI生成过一份暖枫配色的设计稿,它是当初给了博客地址,完全让它自由发挥生成的。我对设计稿还是比较满意就存了下来,从此它就是全站唯一准绳。哦对了,你现在看到的首页那张很浅很浅的水墨江南背景,是我这次我让AI生成的,滚动时钉死在背景上不动,这个改动我很满意。
三、八晚分工
按我自己的记性整理成流水:
- 11 日:设计稿定版,API 骨架搭起来,三个 Gitee 仓库建好(后来加了 mp,一共四个)。
- 12 日:API 全套(文章、分类、评论、RSS、sitemap、后台鉴权与九个内容接口),后台 EleAdminPlus 起步。
- 13 日:后台细节九页,前台首页/列表/详情/搜索/关于/404 逐个成型,老文章全部预渲染出来。
- 14 日:评论系统。三态信任、ip2region 离线库取 IP 归属地、阿里邮件推送、大模型审核。
- 15 日:回复邮件通知、富文本图片水印、logo 换暖色、QQ 登录 + 邮箱验证码。
- 16 日:留言板、全站安全风险自查(改掉存储型 XSS 与 CORS 反射两处)、小程序方案与页面。
- 17 日:生产部署,21:19 开工,对着部署清单一条条过。
- 18 日:挑细节。封面比例、头像、页脚小程序码、点赞做真数据、canonical/OG、站点维护页。
有些指令是我重复了三遍它才记住的:
开发服务器运行在 http://localhost:8088 这个不对,我不是给你了测试域名了吗,接口是 api.aj66.com。
你又忘记了,我本来就要求用 PHP 8.0+ 的呀,因为 thinkPHP 的框架就是 8.0 的。
跨会话记忆比我想象的脆弱。它会把你前天定的规矩忘掉,然后一脸诚恳地重新犯错。所以后来我每晚收尾都补一句:"今天先到这里,更新你的记忆,提交代码。"
四、几个坑,值得单独拎出来讲
1. 预渲染很香,但它把数据烤死了
13 号晚上我第一次撞上这事:
前面我测试了一下评论,我后台审核通过了,但是前台没展示。
原因不在接口 —— API 老老实实返回了新数据。问题是前台用 vite-ssg 预渲染,构建那一刻就把文章、评论、站点配置、友链全都烘焙进了 HTML,还顺手塞了一份 window.__INITIAL_STATE__。浏览器一加载,pinia 状态被快照还原,之后所有"数据已经在了,跳过请求",于是后台不管怎么修改,前台都不为所动。
18 号又撞第二次,就一行字:
后台删了友链,前台不更新。
同一根因,同一套解释。修法不是每次改数据就重构建 —— 那不叫 CMS,那叫手动挡。方案是在客户端挂载后强制刷新一次:把 /config/site、/links、/config/countdown 三个缓存清掉重拉,覆盖旧快照;标记位故意不放进 pinia,否则它自己也会被序列化进产物、把刷新永久关掉。为了证明这玩意儿真起作用,它把一条假友链同时注入到构建产物和快照里,本地起服务实测挂载后假链消失、翻页不重复请求。
顺带一提,年度倒计时从此是每天实时数,不用再重构建。文章列表、热门、归档仍需重构建才更新,这是静态站的门票钱。
2. 伪静态能把自己锁死
17 号深夜切流,我一句"重定向次数太多"把AI喊醒:
前端现在打不开了,显示重定向次数太多。www.anji66.net
原因是那条把 /index.html 301 回 / 的规则 —— 静态站内部的 try_files 本身就靠回落到 index.html 工作,这一跳就成了自己追自己。折腾到凌晨,最后是在 main.js 里把 /index.html 归一成 /,路由认出来了,页面自然打开。十八号零点过,首页吐回 200,196 篇文章页能直访,旧站那些 /code.html、/article/id/123.html 也一条条 301 到了新地址。老搜索引擎的收录不至于断在半夜,这是我这次最在意的一件事。
3. 上线那晚的杂音,几乎都不是代码问题
runtime目录没单独chown www:www,验证码接口 500,报错页一片空白 —— 日志在 root 手里,得先把目录主人交出去;- Redis 密码我先前设成空串
'',ThinkPHP 拿到的是字面量两个单引号,认证直接失败。我自己复盘:"我前面把 redis 的密码设置成了 '',刚才把 '' 给删了。" - 老库是 utf8mb3,
qt_user三列 NOT NULL 缺默认值。要加两个唯一键,先备份 1.4M,再查重,才敢 ALTER; - 站点各自的
open_basedir是墙:维护标记文件必须放在 API 站点目录里,三层共用一个文件才谈得上一致性。
4. 大模型审核:我 key 没填,我的错
18 号上午所有测试评论都卡在待审核,日志写着 reason=模型输出无法解析。我盯着"无法解析"往模型输出格式上想,越查越邪门。它让我翻日志最后几行,才看见 invalid_api_key。
我发现了,我 key 没填,我的错。
教训有两条:一是降级策略别把用户卡死 —— 没凭据就该优雅地转人工,而不是静默判 0;二是报错要看日志,别开 APP_DEBUG,异常页把数据库密码一起吐给访问者,这种蠢事我差点干了。
5. 封面这个 3:2,来回改了四轮
页面有些兼容问题,我们继续做下调整。如图,我原封面图的比例有点被破坏,导致展示不全,另外把图和边框之间做个内边距。
我建议:内边距太大了,只要左上右三个方向留 5 像素边距,下边距不要,另外背景改成白色。
因为之前的封面图有边框不好看,那么就将图片四周裁掉一个像素,然后不要内边距而恢复成之前的填满状态,但要注意图片比例。后续我的封面图都会按照 3:2 的比例上传。
中间它还出过一版 16px 米色卡纸、一版 5px 白衬底,都被我否了。这里头没有任何技术含量,纯粹是我看着别扭。最后定下来:框锁 3:2 满幅出血,图片 object-fit: cover 再放大 1.01 挤掉老封面自带的那圈 1px 描边 —— 老站封面清一色 300×200 且带描边,是当年那个编辑器留下的胎记。以后我自己上传按 3:2,坑就到此为止。
头像同理:先是取作者名首字,永远是个"西";我让它改成"枫";后来又说:
漏了个东西,这个"西"字改成 logo 左半部分的图标吧。
它是用 GD 扫了 logo 图的不透明像素分布,找到图形与文字的分界,一刀一刀裁出 212×208 的透明底图形,一个像素没重绘。小尺寸下里面三个字会糊成一枚橙色小印章,我知情,也还是要它 —— 品牌的东西,统一比清楚重要。
倒是 logo 那三个汉字的封闭区域填色,它拿算法挖得不干净:
算了,撤销吧,挖的不好,回头我自己 photoshop 处理吧。
能撤销,是我愿意用它的最大理由之一。改坏了不心疼,成本几乎为零,所以敢试。
6. 站点维护开关,我让它按默认走
后台那个"站点关闭"配了好几年,一直没怎么用过 —— 因为它只改了数据库里一个字段。这次我说:
这个功能你忘了做。后台配置了站点关闭,前台应显示站点维护的页面,不显示其他内容。
方案是三层读同一个文件:前台伪静态里判断标记文件存在就 rewrite 到维护页;API 中间件对公开接口统一返回 503;小程序读到 site_status 就跳维护提示页。维护页 logo 用 base64 内联,故意不带任何外链资源 —— rewrite 会把 /logo-mark.png 也一起吞成维护页。
有个细节我记一下:必须先传含维护页的前台包,再覆盖 API 文件,最后才改伪静态。维护页文件缺失时 try_files 会回落到 index.html,开关不是白屏,而是静默失效 —— 你以为全站关了,其实什么都没关。
上线前它还提醒我:生产库里 site_status 当前是"关闭",部署完第一件事是回后台把它切回"开启"再保存,否则一点保存就把自己锁在门外。我照做了。
维护页那版,按你默认的处理。
五、这八个晚上,我是怎么跟它打交道的
说点方法,不是给 AI 写评测,是我自己确实靠这几条活下来的。
需求先口述,写清楚"等我指令再开发"。评论系统那三态信任 —— 邮箱匹不匹配用户表、要不要新增用户、实名状态怎么走、大模型审不审、不合规怎么标 —— 我一次性说完,然后加了句"以上你先理解,等我指令"。它列了三条要确认的点,我一条条回答"确认没问题""昵称冲突就取最新提交的""海外邮箱只能人工审核、不自动放行"。定完再动手,返工就少。
截图圈位置,比写十段话省事。"这个模块去掉,把这些数据插入到我刚才指定的地方"、"把左边那个图标的链接也改掉"、"这个不要了,和右边的重复了"。我截图,画个红框,一句话,完事。
一次只让它做一件事,做完立刻验,验完就提交。"让我测试一下后台,然后再做前台,等我指令"、"链接没问题。还有别的问题,改好再提交,我逐个说明"。节奏在我手里,这是效率的关键 —— 一堆改动同时坏掉,人就崩了。后来我索性定了规矩:"下次我说 git 提交,你就本地提交 + push 远程。"
危险的自己来。密钥、密码、.env、宝塔面板、MySQL 交互式 -p,一律不过对话。服务器控制台我本来就是半生不熟,所以它每次都给精确的点击路径,我照着点。命令逐条一行下发,不用分号拼接 —— 粘多行时交互提示会吞掉后面的行,这坑我踩过。
该否掉就否掉。"撤销吧,还是恢复成之前的模样",我说过不止一次。别怕伤它的面子,它没有面子。
六、还没完的事
- 小程序提了审,审核结果还没出。页脚那张正式码已经上线,但发布前扫开会提示小程序不存在 —— 我先发版了,赌的就是审核能过("不用等审核结果,直接打包发版吧")。
- 968px 以下页脚是两列,第五格会留一小块空。看见了,没动。
- 详情页点赞是真数据,去重靠缓存键。我自己测的时候把
art_likes点成了 2,懒得清零,留着吧。 - 收藏做不成真收藏。浏览器脚本写不了书签,改成复制地址 + 提示
Ctrl/⌘+D,这是我认可的现实。
七、几句闲话
八个晚上,两百多条消息(其中一半是终端回显和截图),四十来个页面与接口,六十多项任务清单,四个仓库。十八号晚上我把最后一个尾巴 —— 页脚【交换友链必看】点进去直接到留言板并选中"交换链接" —— 也接上了,全站才算齐活。
要问我什么感受:AI写代码比我快,但它不知道我为什么把博客叫西枫里。名字、slogan、"半路出家,全程修道"那几句,还有那个不肯要蓝紫渐变的固执,只能我自己来。我要做的其实一直是老本行 —— 定审美、控风险、挑毛病、按上线的按钮。所谓"万般皆会,一无所长",如今倒也多一样本事:会指挥。
以前夜里敲代码,是给自己写;这八个晚上敲代码,是跟一个不睡觉的家伙一起写。屏幕还是那块屏幕,角落还是那个角落,只是不用再一个人查文档到两点半了。
枫叶年年红,博客也翻新了一轮。遂记录之。
💬 评论 (0)
填写邮箱验证码用于确认邮箱归你所有;验证通过后该邮箱长期免验证,评论自动快速展示。未验证邮箱的评论一律人工复审。