Facebook回调将'#_ = _'附加到返回URL


479

Facebook回调已开始将#_=_哈希下划线附加到返回URL

有人知道为什么吗?解决办法是什么?


35
知道Facebook 如何附加这些字符吗?Facebook重定向到我的处理程序,然后我在该处理程序中处理到返回URL的重定向,但字符仍附加到URL。
Ben Foster 2012年

4
@BenFoster我想您会发现,如果您使用Fiddler或类似的功能,当FB重新向您的处理程序传递时#_=_,到位,那么即使您对Response.Redirect实际要执行的操作进行访问,浏览器也会保持哈希值,这就是为什么只有下面建议的客户端变通办法才有效。
AakashM

17
2017年,好运
Ejonas GGgg

6
2017年五月,还是....
米尔科

5
2018年3月..yep仍在发生
John Rogerson

Answers:


239

通过Facebook的平台更新

会话重定向行为的更改

本周,当此字段留空时,我们开始向redirect_uri添加片段#____ = ____。请确保您的应用可以处理此行为。

为了防止这种情况,请在登录网址请求中设置redirect_uri,如下所示:(使用Facebook php-sdk)

$facebook->getLoginUrl(array('redirect_uri' => $_SERVER['SCRIPT_URI'],'scope' => 'user_about_me'));

更新

上面正是文档所说的解决此问题的方法。但是,Facebook记录在案的解决方案不起作用。请考虑在Facebook Platform Updates博客文章上发表评论,并关注该错误以获得更好的答案。在此之前,请将以下内容添加到您的head标签以解决此问题:

<script type="text/javascript">
    if (window.location.hash && window.location.hash == '#_=_') {
        window.location.hash = '';
    }
</script>

或更详细的替代方法(感谢niftylettuce):

<script type="text/javascript">
    if (window.location.hash && window.location.hash == '#_=_') {
        if (window.history && history.pushState) {
            window.history.pushState("", document.title, window.location.pathname);
        } else {
            // Prevent scrolling by storing the page's current scroll offset
            var scroll = {
                top: document.body.scrollTop,
                left: document.body.scrollLeft
            };
            window.location.hash = '';
            // Restore the scroll offset, should be flicker free
            document.body.scrollTop = scroll.top;
            document.body.scrollLeft = scroll.left;
        }
    }
</script>

10
哪个字段留空?这是非常神秘的
user210504 2011年

11
@Ryan Update几乎对我有用,最后我仍然得到一个哈希(/#)。对FB不满意。
LenPopLilly 2012年

2
我仍然也得到/#。有人在这里更新吗?删除#号
Tian Loon

6
此解决方案将消除哈希值:<script type =“ text / javascript”> var idx = window.location.toString()。indexOf(“#_ = _”); 如果(idx> 0){window.location = window.location.toString()。substring(0,idx); } </ script>只要确保它是head元素中的第一个标签即可。
Gorgi Rankovski 2012年

1
我在这里注意到您的错误报告:developers.facebook.com/bugs/1424488987806270我也尝试过搜索具有相同结果的“ fragment request_uri”。
瑞安

115

TL; DR

if (window.location.hash === "#_=_"){
    history.replaceState 
        ? history.replaceState(null, null, window.location.href.split("#")[0])
        : window.location.hash = "";
}

完整版及逐步指示

// Test for the ugliness.
if (window.location.hash === "#_=_"){

    // Check if the browser supports history.replaceState.
    if (history.replaceState) {

        // Keep the exact URL up to the hash.
        var cleanHref = window.location.href.split("#")[0];

        // Replace the URL in the address bar without messing with the back button.
        history.replaceState(null, null, cleanHref);

    } else {

        // Well, you're on an old browser, we can get rid of the _=_ but not the #.
        window.location.hash = "";

    }

}

一步步:

  1. 我们只进入代码块,如果fragment#_=_
  2. 检查浏览器是否支持HTML5 window.replaceState方法。
    1. 通过拆分#并仅使用第一部分来清理URL 。
    2. 告诉history将当前页面状态替换为干净的URL。这将修改当前历史记录条目,而不是创建一个新的历史记录条目。这意味着后退和前进按钮将按照您想要的方式工作。;-)
  3. 如果浏览器不支持很棒的HTML 5历史记录方法,则可以通过将哈希值设置为空字符串来尽最大可能清理URL。后退效果不佳,因为它仍会留下尾随的哈希值(example.com/#),并且还会添加历史记录条目,因此后退按钮会将您带回#_-_

了解更多有关history.replaceState

了解更多有关window.location


2
对我来说也很完美。另一种解决方案摆脱了任何查询参数。
AdeelMufti

它对google omniauth做了同样的事情,因此我没有路由匹配就收到错误,它在请求uri https://.....herokua‌pp.com/auth/google_oa‌uth2/callback后附加#(#标签)?状态= 1‌9feaacfe23423jh5jhhGS‌DFwb419049ebb18dabdf8‌&code = 4 / glrY3-mSlTzwe‌rwERTEG334eXcn3hOSxGu‌c51BAlglPa4AU#
Shalafister的

对我来说,它比@Ryan的解决方案更好,因为它不会删除查询。
olivmir '17

该解决方案比Ryan的解决方案更好。经过Facebook的身份验证和Ryan的解决方案后,我将一些参数传递给url,出于某种原因,它只是从url中删除了每个参数。在我的情况下,此解决方案非常有效。
BlueSun3k1

59

如果您要从网址中删除其余的“#”

$(window).on('load', function(e){
  if (window.location.hash == '#_=_') {
    window.location.hash = ''; // for older browsers, leaves a # behind
    history.pushState('', document.title, window.location.pathname); // nice and clean
    e.preventDefault(); // no page reload
  }
})

6
$(窗口)。在( '负荷',函数(E){/ * likebeats的代码* /}作品。
ISHITOYA健太郎

1
我通过更改e.preventDefault()使用此代码;到event.preventDefault();
printf

此代码假设使用jQuery,并且使用onWindowReady事件侦听器作为参数e
Jason Sperske

49

出于安全原因,这是Facebook故意设计的。这是Facebook团队成员Eric Osgood的解释:

这已被标记为“设计使然”,因为它可以防止潜在的安全漏洞。

某些浏览器会将哈希片段从URL追加到重定向到的新URL的末尾(如果新URL本身没有哈希片段)。

例如,如果exam​​ple1.com返回到example2.com的重定向,则转到example1.com#abc的浏览器将转到example2.com#abc,example2.com上的脚本将可以访问example1.com的哈希片段内容.com。

由于可以将一个身份验证流重定向到另一个身份验证流,因此可以使一个应用程序可以访问另一个应用程序的敏感身份验证数据。

通过将新的哈希片段附加到重定向URL来防止这种浏览器行为,可以缓解这种情况。

如果要关注所生成URL的美观性或客户端行为,则可以使用window.location.hash(甚至是您自己的服务器端重定向)来删除有问题的字符。

来源:https : //developers.facebook.com/bugs/318390728250352/


9
这是唯一可以真正解释为什么会发生这种情况的答案,谢谢,我想我将这些令人讨厌的字符留在我的网址中,因为我知道它们不是问题。
stephenmurdoch

1
这也由Tumblr在其重定向中实现。(截至19世纪中期)感谢您对FB的说明。只需将成功的重定向指向“ /#”而不是仅指向“ /”,就可以在简单的Passport应用中轻松解决(这解释了为什么我在网络上看到更多的尾八哥),
RL Brown,

10

不知道他们为什么这样做,但是,您可以通过重置页面顶部的哈希值来解决此问题:

if (window.location.hash == "#_=_")
  window.location.hash = "";

9

您还可以redirect_uri在Facebook回调的参数上指定自己的哈希,这在某些情况下可能会有所帮助,例如/api/account/callback#home。当您被重定向回去时,如果您使用的是ribs.js或类似的文件(不确定jquery mobile),它将至少是一个与已知路由相对应的哈希。


8

Facebook使用框架,框架内部使用AJAX通讯功能。在这种情况下,最大的问题是保留当前页面状态。据我了解,Facebook决定使用模拟锚。这意味着,如果您单击某个位置,它们会模拟为页面内部的锚点,并且在AJAX通信开始时,它们也会更改URL的锚点。

当您尝试重新加载页面时,此解决方案通常会为您提供帮助(而不是ENTER,请按F5),因为您的浏览器会将带有锚点的整个URL发送到Facebook服务器。因此,Facebook会选择最新状态(您所看到的状态),然后您可以从那里继续。

当回调返回时#_=_,表示该页面在离开之前处于其基本状态。由于此锚是由浏览器解析的,因此您不必担心。


2
如果您有像主干网或余烬这样的JavaScript框架,那么这是一个问题,因为路由器解释了哈希后的所有内容
Rudi

1
URL片段标识符(“锚”)不会根据请求发送到浏览器。另外,这个问题是关于OAuth的,而不是主要桌面站点的。这样做的原因是OAuth安全性 -防止由于设计了恶意重定向URI而造成的攻击。
AndrewF

8

非常烦人,尤其是对于解析URI而不是仅读取$ _GET的应用程序而言。

<html xmlns:fb='http://www.facebook.com/2008/fbml'>
<head>
        <script type="text/javascript">
        // Get rid of the Facebook residue hash in the URI
        // Must be done in JS cuz hash only exists client-side
        // IE and Chrome version of the hack
        if (String(window.location.hash).substring(0,1) == "#") {
                window.location.hash = "";
                window.location.href=window.location.href.slice(0, -1);
                }
        // Firefox version of the hack
        if (String(location.hash).substring(0,1) == "#") {
                location.hash = "";
                location.href=location.href.substring(0,location.href.length-3);
                }
        </script>
</head>
<body>
URI should be clean
</body>
</html>

解析未创建的任何数据时,请务必做一些假设。URI片段标识符最早是在RFC 1738(1994年)中指定的,因此,如果您使用正确的URI解析器,这永远不会成为问题。
AndrewF

6

如果您使用带有hashbang(/#!/)URL(例如Angular)的JS框架,这可能会成为一个严重的问题。实际上,Angular会将带有非哈希片段的URL视为无效,并抛出错误:

Error: Invalid url "http://example.com/#_=_", missing hash prefix "#!".

如果是这种情况(并重定向到您的域根目录),请执行以下操作:

window.location.hash = ''; // goes to /#, which is no better

只需做:

window.location.hash = '!'; // goes to /#!, which allows Angular to take care of the rest

1.2+,这很棒。对于1.0及以下版本,请使用window.location.hash ='';
Pradeep Mahdevu 2013年

1
是的,我只在1.2上进行过测试,谢谢您的规范!
neemzy 2013年

然后是html5模式
-rocketspacer

5

我看不到此问题与Facebook AJAX有什么关系。实际上,禁用JavaScript和纯粹基于重定向的登录名也会出现此问题。

与Facebook交换的示例:

1. GET <https://www.facebook.com/dialog/oauth?client_id=MY_APP_ID&scope=email&redirect_uri=MY_REDIRECT_URL> RESPONSE 302 Found Location: <https://www.facebook.com/connect/uiserver.php?[...]>  
2. GET <https://www.facebook.com/connect/uiserver.php?[...]> RESPONSE 302 Found MY_REDIRECT_URL?code=FB_CODE#_  
3. GET MY_REDIRECT_URL?code=FB_CODE#_  

我也只在Firefox上发生过。


4

将此添加到我的重定向页面为我解决了问题...

if (window.location.href.indexOf('#_=_') > 0) {
    window.location = window.location.href.replace(/#.*/, '');
}

1
这会导致窗口位置更改,从而启动页面刷新
rpearce

3

使用角度和角度ui路由器,您可以解决此问题

    app.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {

      // Make a trailing slash optional for all routes
      // - Note: You'll need to specify all urls with a trailing slash if you use this method.
      $urlRouterProvider.rule(function ($injector, $location) {
        /***
        Angular misbehaves when the URL contains a "#_=_" hash.

        From Facebook:
          Change in Session Redirect Behavior
          This week, we started adding a fragment #_=_ to the redirect_uri when this field is left blank.
          Please ensure that your app can handle this behavior.

        Fix:
          http://stackoverflow.com/questions/7131909/facebook-callback-appends-to-return-url#answer-7297873
        ***/
        if ($location.hash() === '_=_'){
          $location.hash(null);
        }

        var path = $location.url();

        // check to see if the path already has a slash where it should be
        if (path[path.length - 1] === '/' || path.indexOf('/?') > -1) {
          return;
        }
        else if (path.indexOf('?') > -1) {
          $location.replace().path(path.replace('?', '/?'));
        }
        else {
          $location.replace().path(path + '/');
        }
      });

      // etc ...
    });
});

不在这里工作了-规则之前的路由变化()应用
MAEL尼松

3

如果您使用的是vue-router,则可以追加到路由列表中:

{
  path: '/_=_',
  redirect: '/', // <-- or other default route
},


2

对我来说,我将JavaScript重定向到另一个页面以摆脱#_=_。下面的想法应该起作用。:)

function redirect($url){
    echo "<script>window.location.href='{$url}?{$_SERVER["QUERY_STRING"]}'</script>";        
}

我认为这不是一个好主意,因为您正在创建多个无用的请求
Jacek Pietal '16

1

一个对我有用的解决方法(使用Backbone.js)是在传递给Facebook的重定向URL的末尾添加“#/”。Facebook将保留提供的片段,而不附加自己的“ _ = _”。

返回后,Backbone将删除“#/”部分。对于AngularJS,请附加“#!” 返回网址应该起作用。

请注意,除非重定向URL也具有片段标识符,否则大多数浏览器都会在重定向时保留原始URL的片段标识符(通过HTTP状态代码300、301、302和303)。这似乎是推荐的行为

如果使用将用户重定向到其他位置的处理程序脚本,则可以在此处在重定向URL后面附加“#”,以用空字符串替换片段标识符。


1

我知道这个回复很晚,但是如果您使用的是passportjs,那么您可能想看看。

return (req, res, next) => {
    console.log(req.originalUrl);
    next();
};

我已经编写了此中间件并将其应用于表达服务器实例,而我拥有的原始URL没有"#_=_"。当我们将passporJS的实例作为中间件应用于服务器实例时,它看起来像这样,它不需要这些字符,而仅在浏览器的地址栏上可见。


3
“#_ = _”仅在客户端上可用。评论:en.wikipedia.org/wiki/Fragment_identifier
alditis

1

我用这个来删除'#'符号。

<script type="text/javascript">
    if (window.location.hash && window.location.hash == '#_=_') {
        window.location.href = window.location.href.split('#_=_')[0];
    }
</script>


0

对于PHP SDK用户

我通过在转发之前删除多余部分来解决此问题。

 $loginURL = $helper->getLoginUrl($redirectURL, $fbPermissions);
 $loginURL = str_replace("#_=_", "", $loginURL);
 header("Location: " . $loginURL);

0

这将删除附加到您网址中的字符

<script type="text/javascript">
 var idx=window.location.toString().indexOf("#_=_"); 
   if (idx > 0) { 
     window.location = window.location.toString().substring(0, idx); 
   } 
</script>

0

删除“#_ = _”(PHP)的最简单解决方案:

而不是“ header(” Location:xxx.php“);” 使用“ echo(” location.href ='xxx.php';“);”

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.