【问题标题】:Facebook Callback appends '#_=_' to Return URLFacebook 回调将“#_=_”附加到返回 URL
【发布时间】:2011-10-31 04:59:04
【问题描述】:

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

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

【问题讨论】:

  • 知道如何 facebook 附加这些字符吗? Facebook 重定向到我的处理程序,然后我处理重定向到返回 url,但字符仍附加到 url。
  • @BenFoster 我想你会发现,如果你使用 Fiddler 或类似的,当 FB 还原到你的处理程序时,#_=_ 就位,那么即使你在你的位置执行Response.Redirect实际上想要这样做,浏览器维护哈希,这就是为什么只有下面建议的客户端解决方法才能工作。
  • 2017,什么鬼
  • 2017 年 5 月,仍然......
  • 2018 年 3 月..是的,还在发生

标签: facebook returnurl


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

    我看不出这个问题与 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。

    【讨论】:

      【解决方案3】:

      最近,Facebook 处理会话重定向的方式发生了变化。有关公告,请参阅本周 Operation Developer Love 博客文章中的“会话重定向行为的变化”。

      【讨论】:

      • 我不确定,他在这里指的是什么
      【解决方案4】:

      通过Facebook's Platform Updates:

      会话重定向行为的变化

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

      为防止这种情况,请在您的登录 url 请求中设置 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>
      

      【讨论】:

      • 什么字段留空?这很神秘
      • @Ryan 更新几乎对我有用,最后我仍然得到一个哈希 (/#)。对 FB 不满意。
      • 我仍然得到 /#。有人在这里更新吗?删除 # 个
      • 此解决方案将清除哈希: 请确保这是 head 元素中的第一个标签。
      • 我在这里注意到了您的错误报告:developers.facebook.com/bugs/1424488987806270 我还尝试搜索“fragment request_uri”,结果相同。
      【解决方案5】:

      非常烦人,尤其是对于解析 URI 而不仅仅是读取 $_GET 的应用程序...这是我拼凑的 hack...享受!

      <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 解析器,这绝不会成为问题。
      【解决方案6】:

      如果你想从 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
        }
      })
      

      【讨论】:

      • $(window).on('load', function(e){ /*likebeats 的代码*/ } 有效。
      • 我通过更改 e.preventDefault(); 来使用此代码到 event.preventDefault();
      • 这段代码假设 jQuery 和一个 onWindowReady 事件监听器接受参数e
      【解决方案7】:

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

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

      【讨论】:

      • 这会导致窗口位置发生变化,启动页面刷新
      【解决方案8】:

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

      【讨论】:

        【解决方案9】:

        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

        【讨论】:

        • 对我来说也很完美。另一种解决方案摆脱了任何查询参数。
        • 它对谷歌omniauth做同样的事情,所以我得到一个错误没有路由匹配,它在请求uri https://.....herokua‌​pp.com/之后附加#(井号) auth/google_oa‌​uth2/callback?state=1‌​9feaacfe23423jh5jhhGS‌​DFwb419049ebb18dabdf8‌​&code=4/glrY3-mSlTzwe‌​rwERTEG334eXcn3hOSxGu‌​c51BAlglPa4AU#
        • 比@Ryan 的解决方案更适合我,因为它不会删除查询。
        • 这个解决方案比 Ryan 的解决方案效果更好。在通过 facebook 的身份验证和 Ryan 的解决方案后,我将一些参数传递给 url,出于某种原因,只是从 url 中删除了每个参数。这个解决方案在我的情况下非常有效。
        【解决方案10】:

        如果您使用带有 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
        

        【讨论】:

        • 1.2+ ,这很棒。对于 1.0 及以下版本,请使用 window.location.hash = '';
        • 是的,我只在 1.2 上测试过,感谢规范!
        • 还有html5模式
        【解决方案11】:

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

        【讨论】:

        • 在这里不起作用 - 在应用 rule() 之前路由会发生变化
        【解决方案12】:

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

        返回时,Backbone 将删除“#/”部分。对于 AngularJS,附加“#!”到返回 URL 应该可以工作。

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

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

        【讨论】:

          【解决方案13】:

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

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

          【讨论】:

          • 我认为这不是一个好主意,因为您正在创建多个无用的请求
          【解决方案14】:

          使用 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),因此不参与路由匹配。

          【讨论】:

            【解决方案15】:

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

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

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

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

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

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

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

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

            【讨论】:

            • 这是唯一能真正解释为什么会发生这种情况的答案,谢谢,我想我会在我的网址中留下有问题的字符,因为我知道它们不是问题。
            • Tumblr 在其重定向中也实现了这一点。 (截至 19 年中期)感谢您指出 FB 解释。在简单的 Passport 应用程序中轻松解决,只需将成功的重定向指向“/#”而不是“/”(这解释了为什么我在网络上看到更多尾随 octothorps,我想......)
            • 对于使用 vue 路由器的人来说,这是一个大问题。因为它会崩溃,因为 vue 路由器需要一个有效的 js 选择器,而这不是,他们可以设置 # 为没有别的,漏洞仍然会得到缓解,但是他们不得不放一些更奇怪的东西,需要肮脏的解决方法
            • 这太胖了 bs 设计它来回惹恼我。如果他们想使用 redirect_url 参数,则允许我们为此目的传递查询参数,否则默认行为将清除它们
            【解决方案16】:

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

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

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

            【讨论】:

            【解决方案17】:

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

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

            【讨论】:

              【解决方案18】:

              PHP SDK 用户

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

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

              【讨论】:

                【解决方案19】:

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

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

                【讨论】:

                  【解决方案20】:

                  如果你使用 vue-router,你可以追加到路由列表中:

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

                  【讨论】:

                    【解决方案21】:

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

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

                    【讨论】:

                      【解决方案22】:

                      对于那些正在寻找简单答案的人 只需添加这个,它对我有用

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

                      也请查看 Paul Schwarz 的完整答案

                      https://stackoverflow.com/a/18305085/2694806

                      【讨论】:

                      • 这只是我的答案stackoverflow.com/a/18305085/2694806的复制/粘贴@
                      • 我只是添加了这个来引用我自己,并更新了答案,链接到你的完整答案所有学分都归你@PaulSchwarz我也指的是你的答案,并且已经投票给你了
                      猜你喜欢
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2018-08-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2014-02-01
                      • 1970-01-01
                      • 1970-01-01
                      相关资源
                      最近更新 更多