Facebookcallback追加'#_ = _'返回URL

Facebookcallback已经开始将#_=_ hash下划线附加到返回URL

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

通过Facebook的平台更新 :

会话redirect行为的变化

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

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

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

UPDATE

以上是正如文件说,以解决这个问题。 但是,Facebooklogging的解决scheme不起作用。 请考虑在Facebook平台更新博客文章留言,并按照此错误获得更好的答案。 在此之前,将以下内容添加到您的head标签来解决此问题:

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

或者更详细的select(谢谢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> 

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用干净的URLreplace当前的页面状态。 这会修改当前的历史logging,而不是创build一个新的历史logging。 这意味着后退和前进button将以您想要的方式工作。 😉
  3. 如果浏览器不支持令人敬畏的HTML 5历史logging方法,那么只要将散列设置为空string,就可以最好地清理URL。 这是一个糟糕的后备,因为它仍然留下一个尾随散列(example.com/#),并且它还添加了一个历史logging条目,所以后退button将带你回到#_-_

了解关于history.replaceState更多信息。

了解关于window.location更多信息。

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

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

出于安全原因,这由Facebookdevise实施。 以下是来自Facebook团队成员Eric Osgood的解释:

这已被标记为“按devise”,因为它可以防止潜在的安全漏洞。

某些浏览器会将散列片段从URL追加到新的URL(如果新URL本身没有散列片段)的末尾。

例如,如果exam​​ple1.com返回一个redirect到example2.com,那么去example1.com#abc的浏览器将转到example2.com#abc,并且来自example1.com的哈希片段内容可以被example2上的脚本访问.COM。

由于可以将一个authenticationstream程redirect到另一个authenticationstream程,因此可以从另一个应用程序访问一个应用程序的敏感authentication数据。

这可以通过在redirectURL中附加一个新的哈希碎片来缓解这种浏览器行为。

如果所得到的URL的美学或客户端行为值得关注,那么可以使用window.location.hash(甚至是您自己的服务器端redirect)来删除违规字符。

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

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

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

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

这个解决scheme通常可以帮助您在尝试重新加载页面时(不是input,按F5 ),因为您的浏览器将带锚的整个URL发送到Facebook服务器。 因此,Facebook拿起最新的状态(你看到的),然后你可以继续从那里。

当callback以#_=_返回时,表示页面在离开之前处于基本状态。 由于这个锚点是由浏览器parsing的,所以你不用担心。

主要恼人的,特别是对parsingURI的应用程序,而不是只读$ _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> 

您也可以在Facebookcallback的redirect_uri参数上指定您自己的散列,这在某些情况下可能会有所帮助,例如/api/account/callback#home 。 当你被redirect回来的时候,如果你使用的是backbone.js或类似的(不知道jquery mobile),它至less会是一个对应于已知路由的哈希。

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

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

如果您处于这种情况(并redirect到您的域根目录),而不是:

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

简单地做:

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

我不明白这个问题是如何与Facebook AJAX相关的。 事实上,JavaScript禁用和基于redirect的login也会出现问题。

与facebook交stream的示例:

 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上。

添加到我的redirect页面解决了我的问题…

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

与angular和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 ... }); }); 

最近在Facebook如何处理会话redirect时引入了一个变化。 请参阅本周的Operation Developer Love博客中的“更改会话redirect行为”。

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

返回后,Backbone将删除“#/”部分。 对于AngularJS,追加“#!” 到返回的URL应该工作。

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

如果您使用将用户redirect到其他位置的处理程序脚本,则可以在这里将“#”附加到redirectURL,以便用空stringreplace片段标识符。

对我来说,我把JavaScriptredirect到另一个页面来摆脱#_=_ 。 下面的想法应该工作。 🙂

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

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

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

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

据我所知,path中的=字符被解释为可选路由参数定义的一部分(请参阅https://angular.io/docs/ts/latest/guide/router.html#ts#optional-route-parameters ),所以不参与路线匹配。

我知道这个回复迟了,但是如果你使用passportjs,你可能想看到这个。

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

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