Facebook回调已开始将#_=_
哈希下划线附加到返回URL
有人知道为什么吗?解决办法是什么?
#_=_
,到位,那么即使您对Response.Redirect
实际要执行的操作进行访问,浏览器也会保持哈希值,这就是为什么只有下面建议的客户端变通办法才有效。
Facebook回调已开始将#_=_
哈希下划线附加到返回URL
有人知道为什么吗?解决办法是什么?
#_=_
,到位,那么即使您对Response.Redirect
实际要执行的操作进行访问,浏览器也会保持哈希值,这就是为什么只有下面建议的客户端变通办法才有效。
Answers:
会话重定向行为的更改
本周,当此字段留空时,我们开始向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>
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 = "";
}
}
一步步:
fragment
是#_=_
。window.replaceState
方法。
#
并仅使用第一部分来清理URL 。history
将当前页面状态替换为干净的URL。这将修改当前历史记录条目,而不是创建一个新的历史记录条目。这意味着后退和前进按钮将按照您想要的方式工作。;-)#_-_
。了解更多有关history.replaceState
。
了解更多有关window.location
。
如果您要从网址中删除其余的“#”
$(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
}
})
e
。
出于安全原因,这是Facebook故意设计的。这是Facebook团队成员Eric Osgood的解释:
这已被标记为“设计使然”,因为它可以防止潜在的安全漏洞。
某些浏览器会将哈希片段从URL追加到重定向到的新URL的末尾(如果新URL本身没有哈希片段)。
例如,如果example1.com返回到example2.com的重定向,则转到example1.com#abc的浏览器将转到example2.com#abc,example2.com上的脚本将可以访问example1.com的哈希片段内容.com。
由于可以将一个身份验证流重定向到另一个身份验证流,因此可以使一个应用程序可以访问另一个应用程序的敏感身份验证数据。
通过将新的哈希片段附加到重定向URL来防止这种浏览器行为,可以缓解这种情况。
如果要关注所生成URL的美观性或客户端行为,则可以使用window.location.hash(甚至是您自己的服务器端重定向)来删除有问题的字符。
不知道他们为什么这样做,但是,您可以通过重置页面顶部的哈希值来解决此问题:
if (window.location.hash == "#_=_")
window.location.hash = "";
Facebook使用框架,框架内部使用AJAX通讯功能。在这种情况下,最大的问题是保留当前页面状态。据我了解,Facebook决定使用模拟锚。这意味着,如果您单击某个位置,它们会模拟为页面内部的锚点,并且在AJAX通信开始时,它们也会更改URL的锚点。
当您尝试重新加载页面时,此解决方案通常会为您提供帮助(而不是ENTER,请按F5),因为您的浏览器会将带有锚点的整个URL发送到Facebook服务器。因此,Facebook会选择最新状态(您所看到的状态),然后您可以从那里继续。
当回调返回时#_=_
,表示该页面在离开之前处于其基本状态。由于此锚是由浏览器解析的,因此您不必担心。
非常烦人,尤其是对于解析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>
如果您使用带有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
我看不到此问题与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上发生过。
使用角度和角度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处理会话重定向的方式进行了更改。有关此公告,请参阅本周的“ Operation Developer Love”博客文章中的“会话重定向行为的更改” 。
对我来说,我将JavaScript重定向到另一个页面以摆脱#_=_
。下面的想法应该起作用。:)
function redirect($url){
echo "<script>window.location.href='{$url}?{$_SERVER["QUERY_STRING"]}'</script>";
}
一个对我有用的解决方法(使用Backbone.js)是在传递给Facebook的重定向URL的末尾添加“#/”。Facebook将保留提供的片段,而不附加自己的“ _ = _”。
返回后,Backbone将删除“#/”部分。对于AngularJS,请附加“#!” 返回网址应该起作用。
请注意,除非重定向URL也具有片段标识符,否则大多数浏览器都会在重定向时保留原始URL的片段标识符(通过HTTP状态代码300、301、302和303)。这似乎是推荐的行为。
如果使用将用户重定向到其他位置的处理程序脚本,则可以在此处在重定向URL后面附加“#”,以用空字符串替换片段标识符。
我知道这个回复很晚,但是如果您使用的是passportjs,那么您可能想看看。
return (req, res, next) => {
console.log(req.originalUrl);
next();
};
我已经编写了此中间件并将其应用于表达服务器实例,而我拥有的原始URL没有"#_=_"
。当我们将passporJS的实例作为中间件应用于服务器实例时,它看起来像这样,它不需要这些字符,而仅在浏览器的地址栏上可见。
使用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) ,因此不参与路线匹配。
对于PHP SDK用户
我通过在转发之前删除多余部分来解决此问题。
$loginURL = $helper->getLoginUrl($redirectURL, $fbPermissions);
$loginURL = str_replace("#_=_", "", $loginURL);
header("Location: " . $loginURL);