JS获取上一访问页面URL地址document.referrer实践

这篇文章发布于 2017年02月13日,星期一,22:55,归类于 JS实例。 阅读 181978 次, 今日 18 次 52 条评论

 

一、JS获取前一个访问页面的URL地址document.referrer

要获取前一个访问页面的URL地址前后端语言都可以,例如PHP的是$_SERVER['HTTP_REFERER'],JavaScript的就是document.referrer

我们平常开发,虽然和URL打交道也算比较频繁,但是,似乎很少使用document.referrer。我起初以为是兼容性不好,后来测试发现ie7都支持,那就奇怪了,为何document.referrer用的不多呢?

我想了一下,可能有下面几个原因:

  1. 后端小伙伴帮我们搞定了相关需求;
  2. 只有一些访问数据统计脚本才非常在意上一个访问页面的url地址是什么;
  3. 如果我们希望实现的功能是返回上一页,可以使用history.go(-1)或者history.back(),我们并不需要知道上一个访问页面具体的地址是什么。

综合以上几点,导致平时开发很少使用document.referrer

但是最近做了一个移动端项目,是我第一次在正式项目中使用document.referrer,这里跟大家分享一下相关的实践。

场景是这样的,移动端无论是原生app还是传统的网页,返回上页是一个比较强烈的需求,如下截图所示:
返回上一页截图示意

几乎所有的内页都有这么一个返回上一页的按钮,例如这个页面(点击体验)

此返回上一页相关HTML代码如下:

<a href="javascript:history.go(-1)" class="header-back jsBack">返回</a>

在大部分场景下,上面办法可以满足我们的交互需求,但是,在有些时候,上面的代码就有些心有力而气不足,因为当前页面的referrer并不总是存在的。

比方说用户是通过微信分享进来的,直接进入了内页,此时是没有上一页的,返回按钮再怎么点击都没有任何反应,就会让用户很奇怪,十有八九会认为是实现了bug,则会让用户对产品的品质抱有疑虑,那问题可就大了。

怎么办呢!后来我想了一招,那就是如果发现浏览器没有上一页来源信息,我们就把返回按钮的链接改成首页的链接地址,这样无论什么时候,用户点击返回按钮一定是会有反应的,并且返回首页从逻辑上讲也是合情合理的。而这里判断是否有没有来源信息就是使用这里的document.referrer,当浏览器得不到上一页的来源信息的时候,document.referrer的返回值就是空字符串'',于是乎,就有类似下面的代码:

if (document.referrer === '') {
    // 没有来源页面信息的时候,改成首页URL地址
    $('.jsBack').attr('href', '/');
}

于是乎,返回按钮的逻辑就天衣无缝了。

二、哪些场景下无法获得上一页referrer信息

  1. 直接在浏览器地址栏中输入地址;
  2. 使用location.reload()刷新(location.href或者location.replace()刷新有信息);
  3. 在微信对话框中,点击链接进入微信自身的浏览器;
  4. 扫码进入QQ或者微信的浏览器;
  5. 直接新窗口打开一个页面; 2017.8.3更新 新版本Chrome测试,新窗口页面依然有document.referrer
  6. 从https的网站直接进入一个http协议的网站(Chrome下亲测);
  7. a标签设置rel="noreferrer"(兼容IE7+);
  8. meta标签来控制不让浏览器发送referer

    例如:

    <meta content="never" name="referrer">

    兼容性如下图:
    meta中的referrers兼容性截图

    iOS浏览器目前还是使用的老版本的规范值,包括:never, always, origin, default。对于Android浏览器,5.0版本开始支持。基本上,在移动端,使用meta标签来控制referer信息的发送与否已经可以在实际项目中使用了。

  9. 等等。

有人可能迫切想知道如何让从https的网站直接进入一个http协议的网站也有document.referrer信息,这方面并不是我擅长的地方,所以我也不清楚应该如何解决此问题,或许需要服务器配置那边配合点什么。

更新于翌日
下面是小新同行的真知灼见:

HTTPS turns off HTTP Referrers to HTTP websites. (默认是关闭的,安全原因。)
开启的话在meta里设置,可能现在的流行的最新版浏览器兼容会好点!
参考:
http://smerity.com/articles/2013/where_did_all_the_http_referrers_go.html
官方这么说的:
https://www.w3.org/Protocols/rfc2616/rfc2616-sec15.html#sec15.1.3

三、结束语

明天情人节,买了巧克力,订了法式大餐,有法式蜗牛,第一次吃,心里总有点毛毛的,让我想起来贝爷,该不会也是那种画风吧。

贝爷吃东西

平时和同事一起吃饭的时候,会传授自己和夫人的相处之道。

很重要的一点就是相敬如宾,大家平等,比方说:当意见不合的时候就听老婆的,当意见统一的时候就听我的。

我也有婆媳问题,我以前的做法是在老婆面前说我妈不是这样的,巴拉巴拉,有用吗,收效甚微,后来我聪明了,一旦老婆大人不开心了,我马上附和:“就是啊,我妈怎么这样啊,在想些什么呢,太离谱了,我这个儿子都看不下去……”,嘿,你别说,只要这么一附和,老婆立马心里就爽了,生气嘛都是生的情绪,你一顺,这态度立马就会转变:“你也别这么说,你妈其实我知道的,就是……我也不是……”,对吧,一下子什么事情就没有,风和日丽,阳光明媚。我呢也可以继续开开心心钓鱼,家和万事兴。

哦呵呵,希望明天一切顺利,明天没得午觉睡了,所以今天要早点休息,12点之前一定要盖上被子。

也祝大家明天节日快乐!

曾经我也是也是一只单身狗,就像下面这样:

单身狗

是前端改变了我的人生。所以,前端在手,美人我有!只要前端学得好,女朋友她跑不了!

(本篇完)

分享到:


发表评论(目前52 条评论)

  1. 农药君说道:

    按照这种方式:
    “`javascript
    if (document.referrer === ”) {
    // 没有来源页面信息的时候,改成首页URL地址
    $(‘.jsBack’).attr(‘href’, ‘/’);
    }
    “`
    其实是比较麻烦的,问题是我们为什么要这么麻烦呢?都已经用了JavaScript link(就是href是JavaScript的链接),我们直接加几十个字符不就行了,你加一个标签,再加几行JavaScript的代码,这不麻烦吗这?
    直接用这个链接不就行了:
    javascript:(document.referrer?() => {window.history.go(-1)}:() => {window.location = ‘/’;})()

    javascript:
    协议限定符,用于规定这个链接实际上是个JavaScript的。

    (document.referrer?() => {window.history.go(-1)}:() => {window.location = ‘/’;})
    这最外层的括号是相当于是把里面所有的输出当做一个能够更加至少是能够把它们聚合起来的,因为里面实际上是两个箭头函数,如果我不用这个括号,那么他有可能会把第二个直接执行

    ()
    这个是用于执行前面那个括号里面的输出,那里面的输出结果无论如何都是一个函数,只不过函数体不同

    document.referrer?() => {window.history.go(-1)}:() => {window.location = ‘/’;}
    格式:a?b:c
    a是指布尔值表达式,b是指如果a的结果为真则返回的值,c是指如果a的结果不为真所返回的值

    () => {}
    参数(名) 箭头函数的箭头 函数体(如果函数体里面只有一条,我们甚至都不用花括号)
    如果没有参数或者参数有多个,则需要使用括号,如果只有一个参数可以直接填写参数名,然后接箭头
    () => {}
    aaa => {}
    (aaa, bbb, ccc) => {}
    如果函数里面有且只有一条函数,可以不用花括号
    () => alert(“123”)
    () => {}
    () => {alert (“123”);alert(“456”);}
    这些是比较基础的箭头函数用法,但是这些只是指定一个箭头函数,想要运行它,要么把它赋值,要么在外侧打一对小括号,然后再在小括号右边再打一对小括号
    () => alert(“123”)()
    上面这个是执行不了的
    (() => alert(“123”))()
    或者
    let aaa = () => alert(“123”)
    aaa()
    才能执行

  2. 钟阳勋说道:

    看个技术博客都有狗粮加餐。???

  3. 小田说道:

    结尾还是sao 2333

  4. Sunny说道:

    最近搜到这篇文章,想看看document.referrer本来该有值但有的浏览器就是为空的解决方式,文中提到,没有document.referrer的情况下可以跳首页,那么跳转到首页之后就会生成一条历史记录,从首页点返回还是回到这个页面,然后再点返回又到首页,永远的死循环了。。。

  5. 小寒说道:

    亲测 window.location.href = window.location.href; 刷新后,document.referrer虽然有信息,但已经是当前页面的URL了。

  6. minitor说道:

    那针对微信登录跳转,我要获取上一个页面的URL地址我该怎么办
    情景是这样的,有一个活动页面点进去跳到微信登录页,登录授权后要返回活动页。

  7. felix说道:

    在IOS中取不到document.referrer一直为空,安卓可以取到,怀疑人生了

  8. 曾小乱说道:

    1,错字:”所以我也不清除应该如何解决此问题”;

    2,通过文章的连接调到《完美人生》这个页面点击返回没反应

  9. 花花说道:

    btn.onclick=function(){document.referrer}没用啊

    • 农药君说道:

      emmm………………
      那个只是获取你甚至都没有对他做操作,哪怕只是打印到控制台(console.log)你都没有做啊

  10. 胖仔说道:

    这个对单页应用,如果使用的是hash, hash变化 document.referrer 不会发生变化的

  11. cityheart说道:

    js圆周运动

    *{ margin:0; padding:0; }
    html,body{ width: 100%; height: 100%; overflow: hidden; }
    .xline{ height: 1px; width: 100%; background:#ccc; position: fixed; top: 50%; left: 0; }
    .yline{ width: 1px; height: 100%; background:#ccc; position: fixed; left: 50%; top: 0; }
    .big-box{ position: fixed; width: 250px; height: 250px; border-radius: 50%; left: 50%; top: 50%; margin:-125px 0 0 -125px; background: rgba(33,33,33,0.1); }
    .box{ position:absolute; left: -25px; top: 50%; margin-top: -25px; width: 50px; height: 50px; background:rgba(33,33,33,0.5); border-radius: 50%; }
    .control{ position: fixed; width: 100px; height: 35px; border-radius: 5px; background: #e3e3e3; color: #333; left: 55%; bottom: 5%; border: solid 1px #ccc; cursor: pointer; outline: none;}

    开始

    $(document).ready(function(){
    var deg = 0, r = $(window).width()/2-$(‘.box’).offset().left-$(‘.box’).width()/2;
    function circleAnimation(deg){
    var x = Math.cos(deg*Math.PI/180)*r, y = Math.sin(deg*Math.PI/180)*r;
    $(‘.box’).css({
    ‘left’: r-x-$(‘.box’).width()/2,
    ‘top’: r-y
    });
    }
    var animation;
    $(‘.control’).toggle(function(){
    animation = setInterval(function(){
    deg += 1;
    if(deg >= 360){
    deg = 1;
    }
    circleAnimation(deg);
    },20);
    $(‘.control’).text(‘暂停’);
    },function(){
    clearInterval(animation);
    $(‘.control’).text(‘开始’);
    });
    });

  12. Circle说道:

    iOS 里面 history.go() 不会刷新 怎么解决呀? 在安卓里面 可以刷新的。

  13. saber说道:

    哇 你竟然撒狗粮

  14. r91说道:

    通过文章的连接调到《完美人生》这个页面点击返回没反应

  15. 海带丝阿飞说道:

    实际业务中还要加入更多的判断
    1. 如果用户是从A网站点击了一个链接跳转到B网站的某个内页, 业务上肯定是希望点击返回跳转到B网站的首页, 但是go(-1)就跳回A网站了
    2. 如果用户在内页进行某个进一步操作的时候需要登录, 登录完毕后自动跳转回原来的内页, 作为已经登录的身份在内页点击返回再回到登录页面也是不符合业务需要的

  16. 酷酷的大米说道:

    张大神,如果说原生app内跳转web页面,使用document.referrer能获取前一个页面的来源吗? 场景:原生app跳转我的页面,点击关闭直接返回,如果是web跳转我的页面,返回上一页

    • 嘻嘻嘻说道:

      应该是不行的,如果我没记错。一般内嵌的H5页面都是新开一个webview,而webview之间的切换是原生方法控制的。。最好的办法是你能让原生开发人员给你封装一个JS调用原生的方法。

  17. 爱哭的小孩说道:

    意见不合听老婆的,意见统一听我的!

  18. stack overflow说道:

    typeof document.referrer === ” 返回false

  19. 流浪的小灰羊说道:

    typeof document.referrer === ”
    是不是写错了啊,印象中typeof 不再存在返回‘’的啊……
    document.referrer === ” 这样吧?

  20. 茄子说道:

    赞!

  21. 技术汪说道:

    看了前面技术部分还挺嗨的,结果一不小心被强行塞了狗粮。不是我军不谨慎,实在敌军太狡猾

  22. 回到过去说道:

    我以前都是用history.length做判断的

  23. 小蛮腰说道:

    整篇文章精华中的精华就在于如何与夫人相处!

  24. 容颜说道:

    高智商与高情商并存,这样的男生请给我来一打…

  25. 思嘉说道:

    最近也在用,看了以后更上一层楼

  26. tians说道:

    边笑边学!棒!。对了,博主可否把书城前端页面源码部分公开呢?

  27. bestRenekton说道:

    鱼哥 把你所有的文章都看完了,,感觉像看完了小说等更新,,有时习惯性的点开却发现没有更新,感觉心里空荡荡的。。。。

  28. 不二很纯洁说道:

    “9.等等。
    有人可能迫切想知道如何让从https的网站直接进入一个http协议的网站也有document.referrer信息,这方面并不是我擅长的地方,所以我也不清除应该如何解决此问题,或许需要服务器配置那边配合点什么。”

    我也不清除应该=>我也不清楚应该

  29. 有容乃大说道:

    前端在手,美人我有??????

  30. AlphaTr说道:

    https 跳转 http referrer 的问题可以看看 Referrer Policy 的相关内容,应该现代浏览器都支持

  31. 小新说道:

    HTTPS turns off HTTP Referrers to HTTP websites. (默认是关闭的,安全原因。)
    开启的话在meta里设置,可能现在的流行的最新版浏览器兼容会好点!
    参考:
    http://smerity.com/articles/2013/where_did_all_the_http_referrers_go.html
    官方这么说的:
    https://www.w3.org/Protocols/rfc2616/rfc2616-sec15.html#sec15.1.3

  32. roming说道:

    这条狗好熟悉啊

  33. meepo说道:

    typeof document.referrer === ”

    是不是

    document.referrer === ”

  34. GreatDujw说道:

    NBility

  35. eddiexxxx说道:

    只要前端学得好,女朋友她跑不了!lol~

  36. 一亿燚说道:

    沙发!