Free Arch_ 解决静态站点 deeplink 404 的问题(以 Taro 框架举例)
共 2100字,需浏览 5分钟
· 2021-10-12
FBI Warning:Free Arch 是我的杜撰,意味着应用的架构全部使用免费资源。该架构服务于像我一样的这种贫穷的个人开发者,目的是在尽可能免费的前提下,为应用打造极致的用户体验(将羊毛薅到无以复加!)。
背景
个人开发者创建的网页站点,希望开放外网访问,首先需要解决部署问题。最佳实践是将站点静态化,从而可以在大量的免费静态站点部署服务中自由选择。如果使用 GitHub 托管代码,当然建议直接使用 GitHub Pages 服务来部署静态站点。
市面上也有大量的专门的免费静态站点生成器,一般这样的部署不会碰到什么问题。但是如果采用了其他的框架开发站点,那么很容易碰到的一个问题是:可以访问首页,点击进入别的页面也没有问题。但是一旦在非首页的页面,按键刷新了页面,或者直接从 deeplink 进入,都会得到一个 404 页面,比如:
现象重述
站点静态化部署后:
站点的 deeplink 页面,从首页点击进入正常展示,直接进入或者刷新就会 404。
站点的首页没有这个问题。
站点如果采用服务器部署,则没有以上问题。比如本地开发时,实际上启动了一个服务器程序,deeplink 是可以直接打开的。
原因
生成的站点文件,根目录下有一个 index.html 文件,从而首页可以正常打开。但是 deeplink 对应的路径,在服务器上没有对应的文件。从首页上点击可以正常显示,是因为框架做了客户端路由,也就是渲染的文件仍然是服务器上根目录下的 index.html 文件,但是这个文件中加载的 javascript,处理了点击并做了后续的渲染。
在有服务器程序运行的情况下,直接打开 deeplink,页面也能正常渲染,是因为服务器程序处理了路由,并对相关的路径返回了某个 html 结果响应,从而正常显示页面。
如果没有服务器渲染程序,而 deeplink 对应的路径在服务器上又找不到响应的文件,自然就是 404 了。
解决办法
原因找到了,解决办法也很简单粗暴,在服务器上直接创建所有的 deeplink 路径就行了。当然也可以运行服务器端渲染程序解决,但这就不是 Free Arch 的范围了。
举个例子
在线演示:https://taro.pa-ca.me/pages/yuque/index
这个例子采用 Taro 框架生成了一个静态站点,通过 GitHub Actions,将 yarn build 后产生的 dist 目录部署在 GitHub pages 服务上。Taro 和很多框架一样,在 build 后生成了一个 dist 目录,但是这个目录下只有一个 index.html 文件,如果你的应用有其他路径,默认是不会为每个路径建立文件夹和相应的 html 文件的。
这里通过在 GitHub Actions 的配置文件中加入一些 shell 脚本,去为所有页面建立文件夹,并且将 dist/index.html 文件复制到相应文件夹下,从而解决了 404 的问题。
首先看下所有的客户端路由页面,在 app.config.ts 文件中:
export default {
pages: [
'pages/yuque/index',
'pages/yuque/article',
'pages/index/index',
'pages/about/index'
],
window: ...
}
除去 yarn build 会自动生成的首页对应 'pages/index/index' 路由外,其他路由都是要自行灌入 shell 脚本的:
name: build
run: yarn && yarn build:h5
# 在 build 完成后做一些 deeplink 工作:
name: deeplinks
run: |
mkdir -p dist/pages/yuque
mkdir -p dist/pages/about
cp -r dist/index.html dist/pages/yuque/index.html
# 注意,不是所有路由都对应为 index.html,但是可以复用 index.html,所以改个名即可:
cp -r dist/index.html dist/pages/yuque/article.html
cp -r dist/index.html dist/pages/about/index.html
继续改进
这个 shell 脚本虽然简单粗暴有效果,但是还可以更加简化和智能化,比如自动解析 app.config.ts 文件,这样不用每次添加新的路由时,需要改动两个地方。或者将这个零散的逻辑封装成一个 GitHub Action,命名为 ghaction-taro-pages 等等。
欢迎留言反馈更好的做法!