Facebook和新Twitter URL中的shebang/hashbang(#!)是用来做什么的?

765

我刚刚注意到,我们现在习惯于使用的冗长而复杂的Facebook URL 现在看起来像这样:

http://www.facebook.com/example.profile#!/pages/Another-Page/123456789012345

就我所知,今年早些时候它只是一个普通的URL片段字符串(以#开头),没有感叹号。但现在它是一个shebang或hashbang(#!),我之前只在shell脚本和Perl脚本中见过。 新Twitter的URL现在也包含#!符号。例如,Twitter个人资料的URL现在看起来像这样:

http://twitter.com/#!/BoltClock

最近Facebook和Twitter的接口都被大量采用Ajax技术,因此在URL中出现#!是否有特殊作用,比如对某些Ajax框架有影响等?
在我的网页应用程序中使用这个会有什么好处吗?


138
嗯,不得不查一下shebang是什么...http://en.wikipedia.org/wiki/Shebang_%28Unix%29 - JYelton
1
这就是我为什么困惑于它为何出现在 Facebook 的 URL 中。 - BoltClock
36
顺便说一句,这不仅适用于shell和perl脚本,而是在类Unix系统上运行的任何脚本。 #!行告诉shell该脚本的解释器是什么... 当然,我的评论与Facebook或Twitter无关。 - bluesmoon
3
谢谢,黑客新闻!(将其留在评论中以便不会提高我的问题,我认为没有必要) - BoltClock
16
哈希井号因为错误的原因而被吹嘘,它破坏最佳实践并破坏了渐进增强和优雅降级的机会。请使用其他可用的解决方案。请参考这里的其他解决方案。 - balupton
2
请注意,自2015年10月起,Google已弃用了2009年引入的哈希符号!因此,对于新应用程序,您不再需要为SEO而这样做。现在,在Google的规范页面顶部只有一个微妙的白色备注:“自2015年10月起,此建议已正式弃用。” - Bart
6个回答

495

这项技术已经被废弃了。(详情请参阅)

之前,此技术通常用于告诉Google如何索引页面。

https://developers.google.com/webmasters/ajax-crawling/

现在,此技术基本被HTML5推出的JavaScript History API所取代。对于像www.example.com/ajax.html#!key=value这样的URL,Google会检查URLwww.example.com/ajax.html?_escaped_fragment_=key=value以获取内容的非AJAX版本。


18
你确定这就是全部吗?我经常发现在Facebook上加载页面时会卡在带有井号的URL上(即使刷新了很多次),但如果手动删除#!,它就可以工作。更不用说你经常会得到“1.5个URL”(即旧的URL仍然存在,并且只是添加了新的部分(即photo.php?id=...两次,但ID不同)。更不用说“#!”也被添加到Facebook邮件的URL中,这些URL可能不会(也不应该)被索引。无论如何,我发现这个井号非常讨厌,因为它似乎是我家里慢速网络上出现那么多页面故障的原因。 - Pedery
11
Facebook有漏洞并不意味着这些漏洞是URL中的两个字符的错误。如果网站编码正确,可以理解和生成它们,可爬取的AJAX URL非常方便。Facebook上还有很多其他问题。 - ceejayoz
16
我只在Facebook上见过这个问题。我同意,这让我非常恼火,每次都让我感到烦躁。(非Facebook平台) - BoltClock
5
就搜索引擎而言,有可索引的 AJAX URL 并不会使页面被索引的可能性大于有可索引的 AJAX URL。Facebook 使用这种 URL 格式不仅是为了 Google 的好处,它还使得通过 AJAX 访问 Facebook 上的页面可被收藏夹收藏,否则将无法被收藏。 - ceejayoz
13
阅读此文章:http://www.isolani.co.uk/blog/javascript/BreakingTheWebWithHashBangs,其中包含一些有趣的警告。 - Michael Stum
显示剩余6条评论

223
在URL中,八角符号/井号/散列符号具有特殊意义,通常用于标识文档的某个部分的名称。确切地说,跟随井号的文本是URL的锚点部分。如果您使用维基百科,您会发现大多数页面都有目录,您可以使用锚点跳转到文档中的各个部分,例如:

https://en.wikipedia.org/wiki/Alan_Turing#Early_computers_and_the_Turing_test

https://en.wikipedia.org/wiki/Alan_Turing 是页面链接,Early_computers_and_the_Turing_test 是锚点。Facebook和其他JavaScript驱动的应用程序(例如我的 Wood & Stones)使用锚点的原因是它们希望使页面可书签化(正如该答案中的评论所建议的那样),或者支持后退按钮而不重新从服务器加载整个页面。

为了支持书签和后退按钮,您需要更改URL。但是,如果您更改页面部分(使用类似 window.location = 'http://raganwald.com'; 的东西)到不同的URL或没有指定锚点,则浏览器将从URL加载整个页面。在Firebug或Safari的JavaScript控制台中尝试此操作。加载http://minimal-github.gilesb.com/raganwald。现在在Javascript控制台中键入:

window.location = 'http://minimal-github.gilesb.com/raganwald';

您将看到页面从服务器刷新。现在输入:

window.location = 'http://minimal-github.gilesb.com/raganwald#try_this';

哎呀!没有页面刷新!输入:

window.location = 'http://minimal-github.gilesb.com/raganwald#and_this';

仍然没有刷新。使用后退按钮可以查看这些URL在浏览器历史记录中。浏览器注意到我们在同一页上但只是更改了锚点,所以它不会重新加载。由于这种行为,我们可以拥有一个单一的Javascript应用程序,它对浏览器来说似乎是在一个“页面”上,但具有许多可书签的部分,并且遵守后退按钮。当用户进入不同的“状态”时,应用程序必须更改锚点,同样,如果用户使用后退按钮或书签或链接带锚点加载应用程序,则应用程序必须恢复适当的状态。

因此,这就是:锚点为Javascript程序员提供了一种机制,使书签、索引和后退按钮友好的应用程序成为可能。这个技术有一个名字:它是一个Single Page Interface

p.s. 这种技术还有第四个好处:通过AJAX加载页面内容,然后将其注入到当前DOM中,可以比加载新页面快得多。除了速度增加外,还可以在程序员的控制下执行进一步的技巧,例如在后台加载某些部分。

p.p.s. 鉴于所有这些,“bang”或感叹号是向Google的网络爬虫发出的进一步提示,即可以从服务器以稍微不同的URL加载完全相同的页面。请参见Ajax Crawling。另一种技术是使每个链接指向一个服务器可访问的URL,然后使用非侵入式的Javascript将其更改为带有锚点的SPI。

这是关键链接:单页面应用宣言


14
如果网络爬虫希望索引一个没有进行此优化的应用程序,它仍然是可抓取的。但实际上并非如此,因为哈希值不会被发送到服务器。 - Chris Broadfoot
7
只作为信息提供:self.document.location.hash 提供了此哈希值的值。 (说明:该代码用于JavaScript编程中,用于获取当前URL的哈希值。) - Kevin
12
哈希值不会被发送到服务器。好发现! - raganwald
40
除了“pps”段落之外,整个回答都是多余的。 - Lightness Races in Orbit
21
我晚了,但是尽管如此,这篇回答的90%完全没有涉及到我关于#!方面的问题。这就是为什么他说它是多余的。这里的点赞数量可能是由于我的问题传到了Hacker News上带来的高流量,再加上这篇答案的篇幅之长所致。 - BoltClock
显示剩余5条评论

113

首先,我是《单页面界面宣言》的作者,被raganwald引用。

正如raganwald所解释的那样,在FaceBook和Twitter中使用的单页面接口(SPI)方法最重要的方面是在URL中使用哈希符号#

字符!仅为了Google的目的而添加,这种标记是Google爬取AJAX密集的网站(极端的单页面接口网站)的“标准”。当Google的爬虫发现一个URL带有#!时,它知道存在另一个传统的URL,在加载时提供相同的页面“状态”。

尽管#!组合对于SEO非常有趣,但只有Google支持(据我所知),通过一些JavaScript技巧,您可以构建适用于任何网络爬虫(Yahoo、Bing等)的SPI网站SEO兼容。

SPI宣言和演示不使用Google哈希!格式,但这种标记可以很容易地添加,并且SPI爬取甚至可以更加容易(更新:现在使用!符号,并保持与其他搜索引擎兼容)。

请看一下这个教程,这是一个简单的ItsNat SPI网站示例,但您可以从中获取其他框架的一些想法,这个示例适用于任何网络爬虫的SEO兼容性。

生成任何(或选择的)“AJAX页面状态”作为纯HTML以供SEO是一个艰难的问题,在ItsNat中非常容易和自动化,同一网站对于SEO可以同时是SPI或基于页面的(或当JavaScript被禁用时为无障碍性)。对于其他Web框架,您可以始终遵循双网站方法,一个网站基于SPI,另一个基于页面用于SEO,例如Twitter使用这种“双网站”技术。


3
什么是渐进增强原则?网站不应因为禁用JavaScript而崩溃或失败。请相信,禁用JavaScript的用户不仅限于过时的浏览器,还包括许多安全意识较强的用户,他们不喜欢执行随机的JS代码。 - Roman Royter

90

如果您正在考虑采用这种哈希符号约定,我会非常谨慎

一旦使用哈希符号,就无法回头。这可能是最棘手的问题。Ben的帖子提出了一个观点,即当pushState得到更广泛的应用时,我们可以摆脱哈希符号并返回传统的URL。但事实是,你不能这样做。我之前说过,URL是永恒的,它们被索引、存档和通常保留下来。除此之外,好的URL不会改变。我们不想与所有有价值的链接断开联系。如果您在任何时候实现了哈希符号URL,然后想要更改它们而不破坏链接,那么您唯一能做的就是在您域名的根文档上运行一些JavaScript代码。永远。这绝不是暂时的,您将会被困住。

您真的想使用pushState而不是哈希符号,因为使您的URL变丑或有可能损坏 -- 永久性地 -- 是哈希符号的巨大和永久性的缺陷。


我认为你对哈希路由的批评是有道理的,但仅使用pushState作为替代方案意味着我们将失去基于URL在单页应用程序中加载内容的能力。因此,URL无法共享。 - Luke
1
我在工作中遇到了类似的问题 - 我们开始使用 Page.js(使用 pushState)进行单页导航,之前我们使用 Hasher 和 Crossroads(基于哈希)。因此,我们需要救援像 /blah#foo/feep/baz?stuff=nonsense 这样的路径。新路径等效于 /blah/foo/feep/baz?stuff=nonsense(请注意,# 被 / 替换)。我只需在我的设置中添加一个路由来捕获 /blah 并检查它是否有哈希,如果有,就在斜杠后附加该哈希的内容。救援完成。 - Gert Sønderby

16
为了更好地跟进所有这些事情,Twitter - 哈希bang URL 和单页界面的先驱之一 - 承认哈希bang系统在长期运行中速度较慢,并且他们已经开始逆转决策并返回老派链接。
相关文章请点击这里

9
我一直认为感叹号!只是表示跟随的哈希片段对应于一个URL,其中!代替了站点根目录或域名。理论上它可以是任何东西,但似乎Google AJAX Crawling API喜欢这样做。
当然,哈希只是表示没有真正的页面重新加载发生,所以是为AJAX目的而设计的。编辑:Raganwald在更详细地解释了这一点。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接