解决跨时区 Nuxt SSR 导致的页面离奇 Bug

打开后台一看,如果本周再不写博客,就三周没更了,还是抽点时间分享点东西吧。今天结合近期解决的问题,分享一下出海服务全球用户,并且使用 SSR 时可能遇到的问题。

问题

我厂的 AI 日记产品 DailyLift 遇到一个非常奇怪的问题。合伙人发现,在午夜过后,打开我们的网页,界面会渲染得非常奇怪。

这里的问题很多,不管是文字样式还是背景图案,都很奇怪,只看错误截图和代码完全没有思路。给不了解我厂产品的读者介绍一下上图中的 bug:

  1. No data 表示当天无数据,正常情况时字体很小。
  2. 只有具体的数字才应该显示成这么大的字体。
  3. 配图也不对,no data 对应的应该是其它图片。
  4. No data 自然不应该有弧形进度条。

难以复现的 bug

我们是远程工作,我一般会把工作时间固定在早上 9:30~晚上 6:30。当我次日开始工作,打开开发环境开始 debug,这个 bug 完全无法重现。对合伙人来说,这个 bug 也是时有时无。所以,这个 bug 在我们的任务列表里开了关关了开,反反复复,非常难搞。

但是随着时间发展,我们还是总结了一些问题特征:

  1. 此问题只在午夜零点之后出现
  2. 此问题只在刚发布过日志之后出现(这个很关键,可惜我解决 bug 那天才发现)
  3. 此问题只在新加载页面时出现
  4. 此问题只在线上(生产 / 测试)环境中出现

至此,我还是没有什么思路,只是觉得,可能要午夜的时候来调试一下。

捕获 bug

上上周,儿子考试结束,我们带他去长沙武汉各玩两天,逛街三天,赶车三次,日均 1w 步之后,我的膝盖很累。导致周三的力量举 PR 测试状态奇差,离既定目标差了一半。(感兴趣的同学可以看下:年中测试新极限,逛街三天赶车两次,状态很差,只完成目标的一边。下次继续努力吧

晚上睡觉前,我心情比较低落,毕竟努力了半年,之前的运动表现估算起来,肯定不止这个数字。于是我就随手打开 DailyLift,写了篇日志。然后,我鬼使神差地想起这个 bug,随手刷新了一下页面,正所谓失之东隅,收之桑榆,竟然复现了这个 bug!

简单介绍一下我们的技术选型:

  1. Nuxt
  2. Supabase
  3. 部署在 Vercel,非企业用户,只能选择特定区域,于是我们选择美西服务器

开发环境无法复现,线上环境稳定复现。虽然表象无法推测问题所在,但也是巨大进步。我思来想去,突然想到,会不会跟服务器端渲染(SSR)有关?于是我查看源代码——注意,是源代码,不是 DOM 树;因为 DOM 树可能会被 Vue(Nuxt)修改过,不是初始状态——一看,果然,服务器端渲染的结果跟我页面的效果不一样。而这样的结果,是由于时区导致的。

我的博客发表在 12 点之前,刷新页面在 12 点之后。如果大家观察上图,可以发现,我们是按照日期来分割数据的。我身处 +8 时区,所以我的 N 日 0 点,是 UTC N-1 日 16 点;Vercel 服务器位于美西,差不多是 -7 时区。于是,Vercel 在服务器端渲染页面的时候,他认为我的这篇日志,应该是 N-1 日 9 点钟写的,N-1 天还没结束,所以是当天(Today)的日志。 但是当我在本地运行 Vue 的时候,我已经是 N+1 日了,于是我本地的代码认为日志发表在昨天,今天还没写过日志。

于是,Nuxt 尝试对 DOM 进行修改,但不知为何,它复用了服务器端传回来的部分 HTML,修改了部分 HTML,所以就出现了前面的 bug。

解决 Bug

找到问题根源之后,解决问题就没那么难了。唯一的难点就是克服测极限带来的身体疲劳,不过找到问题的兴奋感冲淡了这份疲劳。

查阅文档之后我发现,Vercel 倒是早就帮我们准备了解决方案,我们只需要用useRequestHeader('x-vercel-ip-timezone') 就可以获取到用户所在的时区,接下来,只要保证整个 SSR 在这个时区里进行就好。

我使用的 dayjs 来处理时间,它自带 timezone 功能,所以给所有 dayjs() 后面加上 dayjs().tz(tzHeader) 就可以。

总结

最后,困扰我们一个月之久的 Bug 终于解决。我也意识到处理时区在全球化应用开发时的重要性。合伙人问我有没有办法确保类似的问题不再发生,我回他:我这辈子都不会忘了处理时区了……

希望这篇博客对你的出海应用开发有帮助。如果你对 Nuxt、服务器端渲染、云服务器等有问题,欢迎留言讨论。

如果您觉得文章内容对您有用,不妨支持我创作更多有价值的分享:


已发布

分类

来自

标签:

评论

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据