PC端MPA和移动端SPA的路由同构

同一个路由,不同的架构~

不少Web项目都能在端浏览器和PC端浏览器正常显示,比较简单的做法是利用响应式布局,通过媒体查询等方式来使得代码能够在PC端和移动端自适应显示。比如Bootstrap官网就属于此类。

Bootstrap PC端
Bootstrap 移动端

但响应式布局只适合少数逻辑简单,页面较少的网站,对于大中型网站最优的方案还是将PC端项目和移动端项目进行分离,这样既降低了代码的耦合度,同时避免了移动端请求多余的代码。

问题描述

一日,突然被告知官网的一个页面无法访问,点击一试能正常访问。仔细一看消息是从微信发来的,很可能是移动端的问题。

于是在浏览器中使用模拟器访问发现控制台报错,同时http请求返回404。再查看源代码,发现原来是URL地址不对,移动端并没有以html结尾的路由。

但是这个URL是从哪里来的?难道是老版本的URL?

PC端多页应用路由

因为URL以html结尾,很自然地猜测这是PC端路由。

PC端官网是传统的MPA项目,逻辑简单,时间久远。路由由Web服务器nginx来负责处理,直接通过后缀来读取对应的文件并返回。nginx配置文件类似这样:

1
2
3
4
5
6
server {
listen 80;
server_name www.abc.com;
root /xx/yy;
index index.html;
}

移动端单页应用路由

而移动端是基于vue-cli搭建的SPA项目,在vue-router中配置的HTML5模式路由,没有文件后缀。

当然路由能正常运作不但需要浏览器支持HTML5,同时nginx文件也要做对应修改。

1
2
3
location / {
try_files $uri $uri/ /index.html;
}

同时由于移动端和PC端都是用的同一个域名,所以要对浏览器进行判断,只有当设备是移动端时才返回对应页面。完整的nginx配置文件示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
server {
listen 80;
server_name www.abc.com;
root /xx/pc;
index index.html;
location / {
try_files $uri $uri/ /index.html;
# 判断浏览器设备代码太长,此处省略
if(...) {
root /xx/app;
}
}
}

简而言之,默认由nginx服务器来处理路由,展示PC端页面,如果判断为移动端请求,则返回移动端首页,路由交给vue-router来进行处理。

两个项目分别开发于不同时期,采用不同架构,不同的路由。

虽然两个项目能稳定运行,互不干扰,但是各自的路由规则使得URL无法跨平台访问。最佳的体验应该是同一个URL在任何终端浏览器都可以正常访问。要实现这一目的,先来看看各大网站的实现方式~

网站案例

路由同构

移动端和PC端同时都是多页应用,这类项目一般上线时间比较长,同时有SEO需求。例如我们最常用的GitHub

以RxWX项目为例,URL地址同为https://github.com/yalishizhude/RxWX

页面总体积为495KB
页面总体积为77.8KB

PC端和移动端路由完全一致,但是根据浏览器所在不同终端而返回对应的页面。体验非常好,赞一个~\

路由重定向

另一种处理方式还是做路由隔离,但是会对于不同的设备请求转发到对应的正确路径或域名。

比如很多网站的移动端域名就是在PC端域名上加前缀来做区分。
如果把PC端URL放入移动端浏览器打开,那么会跳转到移动端的域名。

但是如果想在PC端浏览器中打开移动端链接,很多网站的转发就失效了。情况变得惨不忍睹了~

比如页面出现类似“老年字体”的放大效果:


比如页面样式基本正确,但是无法使用的:


还有虽然页面未转发,但是页面样式和功能基本正常:

解决方法

那么采用哪种方式来实现比较好呢?

结合以上的案例我们可以看出,路由同构的处理方式体验上来说是比较好的,不需要等待页面跳转,也不会修改原有的URL。
而路由重定向的方式在各大网站上或多或少的存在问题(尚不知是技术原因还是业务上忽视了),而且路由双向的跳转规则处理起来会略微麻烦一些。所以采用路由同构的方式。那到底是改那一端的路由比较好呢?

调整PC端路由

首先考虑修改PC端路由,改为无后缀的方式,与移动端一致。可以考虑在任一处进行修改。

  • nginx服务端。没有想到通用的匹配规则,只能每个页面单独配置,同时每个配置项还需要判断终端类型,可维护性差。
  • 前端页面。需要重新编写脚本进行路由判断,增加代码量。
    所以考虑第二种方式。

调整移动端路由

移动端路由非常好修改,直接在vue-router的配置文件中将路由路径修改成与PC端一致即可。类似下面这样:

1
2
3
4
5
6
7
8
9
10
new Router({
routes: [{
path: '/aa.html',
name: 'aa',
component: aa
}, {
path: '/bb.html',
name: 'bb',
component: bb
})

其他会涉及到路由跳转的地方都可能需要修改,包括router-link组件和$router实例。之所以说“可能”是因为我们在修改路由配置时只修改了path,name并没有修改,所以如果在跳转的时候使用的是path那么必须修改,如果使用的是name则不需要。所以在写代码的时候尽量还是使用name。

部署到生产环境测试,发现同一个路由已经能根据终端类型自动响应了,但是工作真的就完成了吗?

如果在执行npm run dev进入开发模式时,服务端会返回404。因为vue-cli的webpack模板项目,开发时实际上是在本地启动了一个基于Express.js的web服务器,由它来负责相应浏览器请求,面对后缀为html的请求,当然会查找本地对应的文件而不是转发到index.html。所以需要对其进行修改。

找到build/dev-server.js第55行,利用已经使用的connect-history-api-fallback模块,传入重载参数,将以.html结尾的请求都转发到根路径。

1
2
3
4
5
6
app.use(require('connect-history-api-fallback')({
rewrites: [{
form: /\.html$/,
to: '/'
}]
}))

至此,开发环境的404问题解决。

最后

虽然因为公司项目源码不能开放,但是网站还是可供访问的:梯度科技


一部由众多技术专家推荐, 帮你成为具有全面能力和全局视野工程师的进阶利器—— 《了不起的JavaScript工程师》出版了! 点击下方链接即刻踏上进阶之路!


亚里士朱德 wechat
更多WEB技术分享请订阅微信公众号“WEB学习社”