【问题标题】:In a single-page app, what is the right way to deal with wrong URLs (404 errors)?在单页应用中,处理错误 URL(404 错误)的正确方法是什么?
【发布时间】:2013-02-08 18:39:21
【问题描述】:

我目前正在使用 angularjs 编写一个 Web 应用程序,但我认为这个问题适用于任何在客户端进行路由的客户端 javascript 框架 (as angular does)。

在单页应用中,处理错误 URL 的正确方法是什么?

查看几个主要网站,我发现如果您在https://mail.google.com/mail/ 下方输入任何随机 URL,gmail 将重定向到收件箱。这发生在服务器端(使用 http 300 代码)或客户端,具体取决于错误路径是在 # 字符之前还是之后。另一方面,twitter 显示任何无效 URL 的真实 HTTP 404。第三个选项是显示一个“软”404,一个纯粹的客户端错误页面。

这些解决方案似乎适用于不同的情况。 Twitter 希望到 twitter 用户和推文的链接是真正的链接,因此人们可以分享它们,将它们发布在新闻文章中等,因此重要的是要识别无效链接(如果我在我的网站,一个简单的抓取就会告诉我)。另一方面,在 gmail 中,您不应该将链接共享到您的收件箱中,而且我什至不确定这些链接是否真的是永久的/持久的:似乎 url 更新主要用于浏览器历史导航中的目的单页应用。第三种提供软错误的方法可能适用于类似于 gmail 的情况,但没有合理的“默认”页面。

经过这么长的介绍,这里有一些具体的问题:

  • 是否可以接受提供“软”错误页面而不是 404 错误,或者如果 url 无效,单页应用程序是否应该始终重定向到真正的 404?
  • Gmail 的代码可能完全没有错误,但如果确实存在导致无效链接最终重定向回收件箱的错误,那么这可能比错误页面更让用户感到困惑。对于大多数没有像 gmail 那样经过良好测试的网络应用程序,显示错误页面会更好吗?
  • 要为单页应用程序实现真正的 404,似乎有必要在服务器端复制路由逻辑。有没有办法解决这个问题?
  • 当重定向到 404 时,我认为用户应该能够看到导致错误的 URL,可能在 URL 栏中。使用 html5 history api,我认为这可以通过简单地触发当前页面的重新加载(使用错误的 url),结合上面提到的服务器端路由来完成。对于不支持此功能或使用 hashbang 表示法的浏览器,这似乎是不可能的。支持所有浏览器的最佳方式是什么?

【问题讨论】:

  • 您的网站甚至可以在没有 javascript 的情况下运行吗?您是在使用 history.pushState 通过 javascript 更新 URL,还是 URL 中的分段?
  • 另外,你为什么说 redirecting 到 404,为什么不只是 show 一个?
  • @MarkusUnterwaditzer:关于重定向与显示软 404:这是问题的一部分。在某些情况下,显示 404 客户端很好。但我喜欢 HTTP 404 具有自动化工具可以理解的语义(用于测试、检查链接等)这一事实。
  • 对此没有明确的答案。 Armin Ronacher 写了一篇关于 Battlelog 使用的方法的文章:首先渲染站点服务器端,然后使用 Javascript 渲染每隔一次点击:lucumr.pocoo.org/2011/11/15/modern-web-applications-are-here
  • 好吧,那么在你的情况下,只显示一个 404-ish 消息就足够了。

标签: javascript angularjs http-status-code-404 singlepage single-page-application


【解决方案1】:

如果您关心 SEO,angular.io was able to solve this problem(至少与 Google 一样)的方法之一是使用noindex meta tag“指示软 404 状态,这将阻止爬虫爬取页面内容”。显然它可以通过 JavaScript 添加到文档中。

或者,您可以使用 JavaScript 重定向到将响应实际 HTTP 404 状态代码的页面。 Google understands JavaScript redirects 很好。您原来的/does-not-exist 页面,当重定向到/404-error?from=does-not-exist 时,将与服务器返回的404 状态码相关联。 URL 结构无关紧要,这里只有状态码和重定向很重要。

您的其他选项是 SSR(Nuxt.js、Next.js、Angular Universal 等)或预渲染(prerender.io、puppeteer 等),Google 称之为 dynamic rendering,您可以在其中使用预渲染版本,而人类用户获取您的正常客户端渲染应用程序。

【讨论】:

  • ... where you respond to search bot requests with a pre-rendered version while human users get your normal client-side rendered app. 从 SEO 的角度来看,如果用户请求例如是否可以? my-app.com/not-existent-path/blah/blah/blah 并且我的服务器以具有404 HTTP 状态代码的页面进行响应,但是在 404 页面呈现之后,用户按下“转到主页”按钮,按下该按钮时只会更改页面的某些内容并使用 @987654331 @ 不向服务器发出新请求?即,在应用程序通过历史 API 更改 URL 后,以 404 呈现的页面。
  • 听起来不错。如果您使用 JS History API 更改 URL,无论您是要从服务器、缓存还是其他方式获取新内容都没有关系——它对 SEO 没有任何影响,因为搜索机器人不会点击您的“转到主页”链接,他们将改为向该链接中的 URL 发出新请求。 JS History API 仅供您的人类用户使用。
  • 对于任何偶然发现此问题的人,这里有一个关于如何处理软 404 的有趣讨论:youtube.com/watch?v=vjj8B4sq0UI&t=30m15s(31:40 分钟标记)。它是为 JavaScript fwdays 会议准备的,关于为什么 noindex 元标记可能会导致不必要的副作用有一个有趣的解释。
  • @Rose,感谢您的视频。公平地说,如果您在响应本身中添加 noindex 元标记,这只是一个问题。但是,如果您通过 JavaScript 添加它,那么它应该不是问题。为了安全起见,我不会将 noindex 元标记添加为默认值(如 angular.io 所做的那样),而是仅在需要时添加它。
【解决方案2】:

tl;dr: 如果您关心 SEO,请放弃 hashbang 支持并选择PJAX 类似的行为。

您是在制作应用程序还是网站?如果网站需要返回404,以免混淆谷歌。它需要是一个真实的404,而不仅仅是显示找不到页面的消息(即200 带有“找不到页面”的消息非常糟糕)。还有您希望支持哪些浏览器?

我的观点是应该避免整个 hashbang 服务器端渲染(即讨厌的 Google SEO #! hack)。如果不支持 pushstate 的浏览器的 URL 发生更改(不是哈希更改),请使用真正的 pushstate 或重新呈现整个页面。

现在这很重要的原因是#! 永远不应该返回404,因为它没有意义并且不可能模仿服务器端,因为服务器永远不会在不运行 Javascript 的情况下得到#! 之后的内容.

因此,如果您真的关心 SEO,我会做类似 PJAX 的事情,并且只使用真正的 pushstate 进行路由,然后就无法使用旧的 web 1.0。因此,我建议您共享的真正可以是404 的链接不应该有#!(只要页面内容不发生剧烈变化,传统的# 就可以了)。

最后404 不是问题,而是30X 即重定向响应。那是因为浏览器将自动处理重定向,因此您的 Javascript AJAX 调用将永远不会看到30X(他们将获得重定向响应......即 200)。要处理 30X 响应,您必须为每个请求发回一个标头,以指示重定向的 URL 是/曾经是什么(即您被重定向到什么),这样您就不会弄乱 Pushstate 历史记录。

当然,如果您也需要像 Twitter 那样支持 hashbang (and they are the ones that even killed hashbang),您可以利用 Google Sitemaps 和 rel=nofollow 来尝试缓解不良 SEO。

【讨论】:

  • PJAX 对于从头开始构建的人来说看起来很有趣。但是 anuglarjs 框架支持 pushState 开箱即用,所以我想它是不需要的。还是 PJAX 做的更多?
  • 我正在构建的现在是一个应用程序,它不会被搜索引擎索引。但我有兴趣更广泛地理解这个问题。
  • 我不知道 pushState 和 30x 响应的问题。很高兴知道。任何指向文档/示例/教程的指针?
  • 具体来说,pjax-container 似乎在概念上与 angularjs ng-view 相同
猜你喜欢
  • 1970-01-01
  • 2020-12-02
  • 2021-12-16
  • 1970-01-01
  • 1970-01-01
  • 2017-09-20
  • 1970-01-01
  • 2010-11-04
  • 1970-01-01
相关资源
最近更新 更多