Facebook Callback将“#_ = _”附加到返回URL

时间:2011-08-20 13:05:48

标签: facebook returnurl

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

有谁知道为什么?解决方案是什么?

23 个答案:

答案 0 :(得分:231)

通过Facebook's Platform Updates

  

会话重定向行为的更改

     

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

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

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

<强>更新

以上内容正如documentation所说的那样。但是,Facebook的文档化解决方案不起作用。请考虑对Facebook Platform Updates blog post发表评论,然后按this bug获取更好的答案。在此之前,请在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>

答案 1 :(得分:104)

<强> 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. 通过拆分#并仅使用第一部分来清理网址。
    2. 告诉history用干净的URL替换当前页面状态。这会修改当前历史记录条目,而不是创建新条目。这意味着后退和前进按钮将按照您想要的方式工作。 ; - )
  3. 如果浏览器不支持令人敬畏的HTML 5历史记录方法,那么只需将哈希设置为空字符串即可尽可能地清理URL。这是一个糟糕的后备,因为它仍然留下一个尾随哈希值(example.com/#)并且它还添加了一个历史记录条目,因此后退按钮会将您带回#_-_
  4. 详细了解history.replaceState

    详细了解window.location

答案 2 :(得分:57)

如果你想从网址中删除剩余的“#”

$(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
  }
})

答案 3 :(得分:35)

出于安全原因,这是由Facebook设计实现的。以下是Facebook团队成员Eric Osgood的解释:

  

这被标记为'按设计'   因为它可以防止潜在的安全漏洞。

     

某些浏览器会将URL中的哈希片段附加到a的末尾   他们被重定向到的新URL(如果新URL没有   本身有一个哈希片段。)

     

例如,如果exam​​ple1.com返回重定向到example2.com,那么a   浏览器转到example1.com#abc将转到example2.com#abc,并且   来自example1.com的哈希片段内容可供a访问   example2.com上的脚本。

     

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

     

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

     

如果生成的URL的美学或客户端行为是   值得关注的是,可以使用window.location.hash(甚至是   您自己的服务器端重定向)以删除违规行为   字符。

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

答案 4 :(得分:10)

不确定他们为什么会这样做但是,你可以通过重置页面顶部的哈希来解决这个问题:

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

答案 5 :(得分:9)

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

答案 6 :(得分:8)

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

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

当回调返回#_=_时,表示该页面在离开之前处于基本状态。因为浏览器会解析此锚点,所以您无需担心它。

答案 7 :(得分: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>

答案 8 :(得分:6)

如果你使用带有hashbang(/#!/)URL的JS框架,这可能会成为一个严重的问题。角。实际上,Angular会将带有非hashbang片段的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

答案 9 :(得分: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。

答案 10 :(得分:4)

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

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

答案 11 :(得分: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 ...
    });
});

答案 12 :(得分:2)

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

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

答案 13 :(得分:2)

最近,Facebook处理会话重定向的方式发生了变化。请参阅本周{@ 3}}博客文章中的“改变会话重定向行为”。

答案 14 :(得分:2)

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

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

答案 15 :(得分:1)

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

返回后,Backbone将删除“#/”部分。对于AngularJS,附加“#!”返回URL应该有效。

请注意,大多数浏览器在重定向(通过HTTP状态代码300,301,302和303)时保留原始URL的片段标识符,除非重定向URL也具有片段标识符。这seems to be recommended behaviour

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

答案 16 :(得分:1)

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

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

我已经编写了这个中间件并将其应用于表达服务器实例,而我得到的原始URL没有"#_=_"。当我们将passporJS实例作为中间件应用于服务器实例时,它看起来就像它,它不接受这些字符,但只能在我们浏览器的地址栏上看到。

答案 17 :(得分:1)

我使用这个,也删除'#'符号。

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

答案 18 :(得分:0)

使用Angular 2(RC5)和基于散列的路由,我这样做:

const appRoutes: Routes = [
  ...
  {path: '_', redirectTo: '/facebookLoginSuccess'},
  ...
]

export const routing = RouterModule.forRoot(appRoutes, { useHash: true });

据我了解,路由中的=字符被解释为可选路由参数定义的一部分(参见https://angular.io/docs/ts/latest/guide/router.html#!#optional-route-parameters),因此不参与路由匹配。

答案 19 :(得分:0)

对于PHP SDK用户

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

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

答案 20 :(得分:0)

这将删除URL中附加的字符

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

答案 21 :(得分:0)

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

代替“ header(“ Location:xxx.php”);“使用“ echo(” location.href ='xxx.php';“);”

答案 22 :(得分:0)

对于那些正在寻找简单答案的人

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