【前端 CDN】CDN缓存造成的bug,JS识别移动端设备和PC端设备,域名重定向

目录

一、项目问题和原因

二、解决方案

2.1 前端入口文件识别

2.2 pc 端和 mobile 端域名拆分

三、遗留问题处理

3.1 pc 端处理


一、项目问题和原因


背景:

  • 项目使用原生端开一个 webview壳,访问服务器前端地址
  • 项目分为 pc 端和 mobile 端,分为两个工程
  • 用户在 pc 端和 mobile 端都是使用一模一样的域名访问,由 nginx 根据用户的 UserAgent 转发到对应的地址
  • 服务器加了CDN

 

现象:

正式环境中,用户在 mobile 端访问时,却访问到了 pc 端的页面,由于文件访问是相对路径访问的,访问了错误的页面,拿不到对应的资源,故报错。同理,用户在 pc 端访问时,却访问到了 mobile 端页面。

 

原因:

1. 购买的CDN服务器不支持根据UserAgent转发到对应文件(有的CDN支持)

2. 由于 pc 端和 mobile 端使用了同一个域名访问,在CDN对这个文件访问的存储,可能是 pc 的,也可能是 mobile 的。导致 pc 端用户用地址去访问文件,拿到了 mobile 端的页面,或是 mobile 端用户用地址去访问文件,CDN返回的是 pc 端的文件。

3. 若是一整套文件都相同,用户最多访问到不同的文件,但CDN存储的使用文件中,会出现 mobile 端文件和pc文件混杂的情况,故会拿不到资源文件,导致报错

 

二、解决方案


思考了多种解决方案,最终决定使用pc端访问地址和 mobile 端访问地址分开的做法(2.2)。

2.1 方案一、前端入口文件识别

在项目的入口文件上(一般是index.html),加入一段js代码,通过获取userAgent判断是否访问到了正确的设备,若不正确,则重定向。

若不是在入口文件识别,而是使用外链的方式加载js,由于已经拿到了错的文件了,通过相对路径去拿地址肯定也是拿不到的。

故直接内嵌在入口文件的头部。

如 mobile 端的入口文件:(pc端同理)

<!-- index.html -->

<!DOCTYPE html>
<html lang="zh" dir="ltr">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" id="setscale" content="viewport-fit=cover, width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
  ...
  <script type="text/javascript">
    let type;
    // 判断用户是哪种设备
    if ((navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i))) {
      type =  "mobile"
    } else {
      type =  "pc"
    }
    // 若不是mobile设备,重定向到pc
    if(type != 'mobile')  window.location.replace(window.location.origin + "/ index");
  </script>

  <link href="build/main.css?v=5.5" rel="stylesheet">

</head>
<body>
...
</body>
</html>

 

2.2 方案二、pc 端和 mobile 端域名拆分

将 pc 端和 mobile 端的域名进行拆分,将顶级域名 testUrl.com 和主域名 www.testUrl.com 指向 pc 项目,将子域名 m.testUrl.com 指向 mobile 项目。用户通过不同的域名访问项目。

由于CDN缓存是根据访问路径缓存的,当区分开 pc 端项目路径和 mobile 端项目路径后,用户访问的文件就不会在混乱了。

 

三、遗留问题处理


使用 2.2 中的办法解决了用户访问的问题,但是如果用户不重新下载APP,或是直接在 web 上访问旧线路,就依旧会报错。如何引导用户正常使用线路?

3.1 pc 端处理

3.1.1 判断当前是 pc 端还是 mobile 端

var myBrowser = {
    versions: function () {
    var u = navigator.userAgent;
    return {//移动终端浏览器版本信息
        trident: u.indexOf('Trident') > -1, //IE内核
        presto: u.indexOf('Presto') > -1, //opera内核
        webKit: u.indexOf('AppleWebKit') > -1, //苹果、谷歌内核
        gecko: u.indexOf('Gecko') > -1 && u.indexOf('KHTML') == -1, //火狐内核
        mobile: !!u.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i), //是否为移动终端
        ios: !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/), //ios终端
        android: u.indexOf('Android') > -1 || u.indexOf('Linux') > -1, //android终端或者uc浏览器
        iPhone: u.indexOf('iPhone') > -1 || u.indexOf('Mac') > -1, //是否为iPhone或者QQHD浏览器
        iPad: u.indexOf('iPad') > -1, //是否iPad
        webApp: u.indexOf('Safari') == -1, //是否web应该程序,没有头部与底部
        wx: u.indexOf('MicroMessenger') > -1,//是否是微信
        hasVersion: u.indexOf('Version') > -1,
        isie: navigator.userAgent.toLowerCase().indexOf(".net") > 0 || navigator.userAgent.toLowerCase().indexOf("msie") > 0,
        isie6: navigator.userAgent.toLowerCase().indexOf("msie 6.0") > 0,
        isie7: navigator.userAgent.toLowerCase().indexOf("msie 7.0") > 0,
        isie8: navigator.userAgent.toLowerCase().indexOf("msie 8.0") > 0,
        isie9: navigator.userAgent.toLowerCase().indexOf("msie 9.0") > 0,
        ischrome: navigator.userAgent.toLowerCase().indexOf("chrome") > 0 && navigator.userAgent.toLowerCase().indexOf("safari") > 0,
        issafari: navigator.userAgent.toLowerCase().indexOf("chrome") < 0 && navigator.userAgent.toLowerCase().indexOf("safari") > 0,
        isfirefox: navigator.userAgent.toLowerCase().indexOf("firefox") > 0
    };
} ()

 

3.2.2 跳转错误则弹出提示,修改域名,并进行重定向

if(myBrowser.versions.mobile) {
    var jumpUrl = window.location.origin;
    var alertContent = '<div class="pcAlertWrap"><div class="pcAlert"><p class="pcAlertText">请下载最新版本</p><div class="btnWrap"><div class="closeBtn">确定</div></div></div>'

    var isApp = false;
    // 若window.android_Web不是undefined,则是在安卓的web浏览器中
    if((myBrowser.versions.android && window.android_Web != undefined)) {
        isApp = true;
    } else if(myBrowser.versions.ios) {
        try {
            isApp = true;
            window.webkit.messageHandlers.testAAApp.postMessage('')
        } catch (error) {
            isApp = false;
        }
    }
    if(isApp) {
        // 若在app中,则提示下载最新版本
        alertContent = `<div class="pcAlertWrap"><div class="pcAlert"><p class="pcAlertText">请下载最新版本<div class="btnWrap"><div class="sureBtn">确定</div></div></div>`
    } else {
        // 若在web中,则重定向到m.的网址去
        // 若是主域名
        if(jumpUrl.indexOf('://www') > 0) {
            jumpUrl = jumpUrl.replace('://www', '://m')
        }
        // 若已经是移动端的二级域名,则无需操作
        else if(jumpUrl.indexOf('://m.') > 0){
        } else {
            // 若是顶级域名,则插入m.
            jumpUrl = jumpUrl.replace('://', '://m.')
        }
        alertContent = `<div class="pcAlertWrap"><div class="pcAlert"><p class="pcAlertText">请使用 <a href="${jumpUrl}">${jumpUrl}</a> 访问获得更佳体验</p><div class="btnWrap"><div class="sureBtn">确定</div></div></div>`
    }
    window.onload = function() {
        $('body').append(alertContent);
        $('.pcAlertWrap').addClass('active');
        $('.closeBtn').on('click',function(){
            $('.pcAlertWrap').removeClass('active');
        })
        $('.sureBtn').on('click',function(){
            $('.pcAlertWrap').removeClass('active');
            window.location.replace(jumpUrl)
        })
    }
}

3.3.3 css 样式

<style>
    .pcAlertWrap{
    position: fixed;
    left: 0;
    top: 0;
    bottom: 0;
    right: 0;
    background: rgba(0,0,0,0.5);
    -webkit-box-align: center;
    -webkit-align-items: center;
    -ms-flex-align: center;
    align-items: center;
    justify-content: center;
    z-index: 99999;
    display: none;
    }
    .pcAlertWrap.active{
    display: -webkit-box;
    display: -webkit-flex;
    display: -ms-flexbox;
    display: flex;
    }
    .pcAlert{
    position: relative;
    width: 300px;
    min-height: 150px;
    background: #fff;
    padding: 10px;
    font-size: 14px;
    border-radius: 5px;
    z-index: 1;
    }
    .pcAlertText{
    margin-top: 10px;
    text-align: center;
    }
    .btnWrap{
    position: absolute;
    width: 100%;
    right: 0;
    bottom: 10px;
    text-align: center;
    color: #fff;
    font-size: 14px;
    z-index: 999;
    }
    .closeBtn,.sureBtn{
    display: inline-block;
    margin: 0 10px;
    width: 70px;
    height:30px;
    line-height: 30px;
    background: #0000FF;
    border-radius: 4px;
    
    }
</style>

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值