V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Aether
V2EX  ›  程序员

微信浏览器开发,后退时强制刷新的解决方案

  •  
  •   Aether ·
    aetherwu · 2016-11-21 19:35:54 +08:00 · 21945 次点击
    这是一个创建于 2922 天前的主题,其中的信息可能已经有所发展或是发生改变。
    和这破事儿逗逼了三天,试过各种办法,包括而不限于 onpopstate/onpageshow/ onload ,也试过本地数据缓存读写,还用过 AJAX 更新,都可耻地失败了——很神奇的是,在 Andorid 和微信自家的模拟器上都有效果,唯独在 iOS 的浏览器上失败。

    我想要的很简单,就是当 Javascript 调用 history.back() 或者 history.go(-1) 时,微信浏览器可以自动刷新前面调用过的历史页面。而在 iOS 的微信上,唯独 location='' location.href='' history.go(0) 这几句就是死活无效。

    最后被逼无赖,解决方案还是要靠 URL 上的随机数,也就是在当前打开的页面添加随机数:

    var rnumber = Math.floor(Math.random()*1000)
    history.replaceState({mod: rnumber}, 'Title', '?mod='+rnumber);

    然后下一个页面调用 history.back() 回来的时候,这个代码会生成新的 URL ,从而强制微信判断为不同的页面,达到强制刷新的目的。

    完成这个技术 hack 的目标是,在 Web page (纯页面,非 Web app )的体系内,保持友好的「返回」体验,否则在页面上填写一个表单,点击提交以后,点击「返回」会返回填写表单的界面。虽然在逻辑上这里也没错,但是现在的体验都在向 APP 靠拢,故有此一折腾。。。


    细节描述:
    1 、在当前 view 添加随机值,可以动态判断,仅对编辑者有效:
    var rnumber = Math.floor(Math.random()*1000)
    history.replaceState({mod: rnumber}, 'Title', '?mod='+rnumber);

    2 、用户点击进入编辑页面(无变化)

    3 、在 POST 后的编辑页面输出
    history.go(-2)
    将浏览历史回退

    4 、前述的第一个页面会因为 javascript 的原因生成新的随机 URL ,导致微信浏览器识别为新的资源而强制刷新,从而加载编辑后的新内容。

    5 、此时用户点击左上角「返回」,会按原路返回「上一级」(而不是 Web page 中的上一页概念)。

    此方案在我手边的环境里测试有效(但不能担保对所有特别是对安卓全阵营有效)。
    网上没找到特别明确的解决方案,所以这里特别记录分享一下,也许会对其他朋友有用。
    第 1 条附言  ·  2016-12-26 16:17:12 +08:00
    我更新一下。。。发现随机数会导致分享 SDK 的签名失效(一脸懵逼)
    第 2 条附言  ·  2016-12-27 12:36:30 +08:00

    这是35天后的一个更新(第一个 APPEND 是昨天,这是第二个)

    现在我去掉了随机数,因为必须保证微信分享 SDK 验证过关,而我不想在本地 JS 做校验(其实是懒得改/也没有必要每次刷新都做一次)。 我现在的做法:

    1、统一跳转到一个 backstep.html 的模板页面 2、backstep 写入本地 localStorage,值为希望回退的步数(比如2或者3) 3、然后通过 location.replace 将一个目标页面刷新:

    比如:

    localStorage.setItem("back2steps", "{{backsteps|default(2)}}");
    location.replace("{{url}}")
    

    4、在新的页面,读取 localStorage 并且将其重置为空 5、如果读取到 localStorage 数字,那么将 history 调回 N 步,这个时候因为此页面已经在当前刷新过了,所以看上去就是刷新过的。

    例如:

    window.onpageshow = function(){
    	detectBackStes = parseInt(localStorage.getItem("back2steps"));
    	if(detectBackStes>0){
    		localStorage.setItem("back2steps", "");
    		window.scrollTo(0,1)
    		history.go(-detectBackStes);
    	}
    }
    

    以上,非常脏的做法,用户可能会有轻微的闪烁感(如果页面很轻则可能感觉不出来)。 但至少实现了我现在想要的部分目标。

    我还是应该实际些。。。考虑去开 VUEJS 技能点 T_T

    9 条回复    2016-12-24 19:56:33 +08:00
    jininij
        1
    jininij  
       2016-11-22 00:25:56 +08:00 via Android
    之前也被这问题困扰了一整天,最后不得不以一个特别变态的方法实现:用 js 拦截所有 a 跳转,并复写 window.location 。如果页面试图跳转,就往 localStorage 里记录一下,再主动去跳转。然后用定时循环不断检查 localStorage 。
    写回复的时候突然又想到一个方法,页面到后台后, setTimeout 会被暂停,而微信的页面只能现实一个窗口,所以针对其他多窗口的浏览器,页面不在活动页面时 setTimeout 优化不会发生在微信上。这一点也可以用来 hack 一下。
    DreGD
        2
    DreGD  
       2016-11-22 08:57:18 +08:00 via Android
    同加过随机数
    DreGD
        3
    DreGD  
       2016-11-22 08:58:46 +08:00 via Android
    依稀记得是 200 from cache 而不是 304
    leohxj
        4
    leohxj  
       2016-11-22 13:32:30 +08:00
    浏览器有一个机制叫做 Back-Forward Cache : https://developer.mozilla.org/en-US/docs/Working_with_BFCache
    不知道是否有帮助。
    nosun
        5
    nosun  
       2016-12-24 18:25:11 +08:00
    按照楼主的方案,试了下,没成功,返回之后页面没强制刷新,能看到 url 上退回去的时候随机数变了。

    怎么破,就是想在使用手机的后退按钮返回时,需要强制刷新页面。否则页面是空白的。
    Aether
        6
    Aether  
    OP
       2016-12-24 19:15:47 +08:00
    @nosun 什么系统?什么浏览器?微信版本号?手机的后退按钮要比程序回退应该要简单些,你测试一下 onpageshow 部分?
    nosun
        7
    nosun  
       2016-12-24 19:47:37 +08:00
    安卓 6.0 微信 6.3.32 , 浏览器不知道怎么看
    nosun
        8
    nosun  
       2016-12-24 19:50:01 +08:00
    我这边是在微信中嵌入了一个 web 页面,中间是 ajax 加载了一些数据,现在后退了, ajax 那部分不响应,主要是这个问题,试过 ajax + 时间戳, cache 设置为 false 都不管用。手动刷新一下就可以。在微信的模拟器中也是这样。
    nosun
        9
    nosun  
       2016-12-24 19:56:33 +08:00
    嗯,我再看看
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5150 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 09:18 · PVG 17:18 · LAX 01:18 · JFK 04:18
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.