我把一款网页游戏发布上线了。
自己的电脑能运行。GitHub 里已经是修正后的代码。部署流程也显示成功。
可到了部分手机上,游戏还是会出错。
Analytics 里留下的报错是:
SyntaxError: Unexpected token '<'
我明明写的是 JavaScript,为什么突然冒出来一个“<”?
这是我在制作网页游戏 ORA Quest 时真实遇到的问题。后来我发现,最有价值的并不是某一行“神奇修复代码”,而是弄懂这个报错到底在暗示什么。
真正有问题的,可能根本不是“<”
一开始我以为是 JavaScript 语法写错了。是不是混进了奇怪字符?JSON 坏了?少了一个逗号?
但遇到 Unexpected token '<' 时,很值得先检查一件事:浏览器本来要读取 JavaScript 或 JSON,服务器却是不是返回了 HTML。
比如浏览器请求 game.js,理应拿到 JavaScript。可服务器实际上返回的是一个从 <!DOCTYPE html> 开始的错误页面。
浏览器仍然把它当 JavaScript 解析,于是在第一个 < 就失败了。
也就是说,报错看起来在骂这个符号,真正的问题却可能是:浏览器拿到了不该拿到的文件。
最麻烦的是:它不一定对所有人都坏
这正是这次问题最折磨人的地方。
不是“所有人都进不去”。电脑能跑,某些手机也能跑,但另外一些手机或社交 App 内置浏览器却会失败。
于是很容易陷入这种循环:
改代码 → 部署 → 用自己的电脑打开 → 能运行 → 以为修好了。
我以前也会这样判断。现在不会了。
如果问题和缓存、浏览器、旧资源或特定请求路径有关,那么开发者自己的设备反而可能给出“已经没问题”的假象。
现在再遇到,我会先查这 5 件事
- 直接打开出错的 JS 或 JSON URL。
- 确认返回内容真的是 JavaScript 或 JSON。
- 检查是否返回了 404、登录页、WordPress 页面或其他 HTML。
- 确认线上服务器提供的文件,和 GitHub 中预期的文件一致。
- 换设备、换浏览器,并尽量排除同一缓存的影响后再测试。
其中第一步尤其重要。
与其看到“JavaScript 报错”就不停改 JavaScript,不如先问一句:
这个 URL 到底返回了什么?
这一个问题,往往能省掉很多无效修改。
GitHub 里正确,不代表用户拿到的就正确
这也是我这次被狠狠教育的一点。
代码仓库里的版本没问题,并不等于用户端收到的一定是那个版本。
中间还可能经过自动部署、服务器、WordPress、缓存、浏览器缓存,以及各种 App 内置浏览器。
只要其中一层还在返回旧文件或意外响应,就会出现“我明明已经修了,为什么用户那里还是坏的”。
所以我现在对“修好了”的定义变了。
不是 commit 正确就算修好,而是生产环境的真实 URL 在接近真实用户的条件下也能正常运行,才算结束。
别只想着消灭报错,还要让下次更容易查
以前一出错,我只想赶快把它弄没。
现在我还会考虑:如果它再出现,我能不能更快知道原因?
是哪个文件失败了?请求的是哪个 URL?用户是什么环境?运行的是哪个 build?
有了这些信息,下次就不再只是“又出现同一个怪错了”,而是可以判断“这和上次是不是同一个原因”。
这种工作不酷,但对一个人维护线上服务来说,可能比多做一个新功能更值钱。
个人开发,很多时候不是“会不会写”,而是“能不能看清到底发生了什么”
开始做网页游戏以前,我以为开发主要是写故事、做角色、写程序。
真正做起来后,大量时间花在了这些问题上:
为什么只有这台设备不行?为什么昨天的 JavaScript 还在?为什么 JSON 地址返回的是 HTML?
每弄明白一个问题,我能做的东西就会多一点。
这次 Unexpected token '<' 给我留下的最大教训是:
“我写下的代码”和“用户实际收到的文件”,并不总是一回事。
如果你现在正被这个错误折磨,先别急着重写代码。直接打开那个出错的 JS 或 JSON URL。要是看到的是 HTML,那已经是非常重要的线索。
我正一边踩这些坑,一边制作网页游戏 ORA Quest。如果你想看看这些排错最后变成了什么,可以免费试玩 ORA Quest。

コメント