如何让反应路由器响应 404 状态码?

Posted

技术标签:

【中文标题】如何让反应路由器响应 404 状态码?【英文标题】:How to let react router respond with 404 status code? 【发布时间】:2016-07-03 07:58:08 【问题描述】:

我以 root 身份使用 react 路由器,“/”下的所有请求都被定向到 react 路由器。并且当 react router 发现 url 与任何定义的组件都不匹配时,它会使用 NoMatch 组件进行渲染。问题来了,NoMatch 被渲染,这就是我想要的,但状态码仍然是 200 而不是 404。当我的 css 或 js 文件被放置在错误的 url 上时,react router 会做同样的事情,它会响应 200 !然后页面告诉我我的资源内容类型有问题!

那么,我怎样才能使用 react router 来处理“/”中的所有内容,并且仍然让它正确处理 404 错误(以 404 状态码响应)?

反应路由器中的代码

render((
  <Router history=browserHistory>
    <Route path="/" component=App>
      <IndexRoute component=Index/>
      <Route path="archived" component=App>
        <IndexRoute component=ArchivedPage/>
        <Route path="project/:projectId" component=ArchivedDetailPage/>
      </Route>
      <Route path="*" component=NoMatch/>
    </Route>
  </Router>
), document.getElementById('app'));

服务器端

  router.use('/', function(req, res, next) 
    res.render('index-react', 
      title: 'some title'
    );
  );

【问题讨论】:

你已经想到了什么?分享一些代码 现在提供代码 我添加了那个道具,但是反应路由器没有处理这个,它不会发出状态 404 错误。是否可以通过 javascript 发出 404 状态错误? 【参考方案1】:

使用 react-router 2.0.0 你可以:

<Route path="*" component=NoMatch status=404/>

编辑:

您需要做的是在您的路由定义上创建一个自定义属性,如您在上面看到的(状态)。

当您要在服务器端渲染组件时,请检查此属性并发送带有此属性代码的响应:

routes.js

import React from 'react';
import IndexRoute, Route from 'react-router';

import 
    App,
    Home,
    Post,
    NotFound,
 from 'containerComponents';

export default () => 
    return (
    <Route path="/" component=App>

        <IndexRoute component=Home />
        <Route path='post/' component=Post />

         /* Catch all route */ 
        <Route path="*" component=NotFound status=404 />

    </Route>
  );
;

server.js:

import  match  from 'react-router';
import getRoutes from './routes';
....
app.use((req, res) => 
match( history, routes: getRoutes(), location: req.originalUrl , (error, 
        redirectLocation, renderProps) => 
        if (redirectLocation) 
          res.redirect(redirectLocation.pathname + redirectLocation.search);
         else if (error) 
          console.error('ROUTER ERROR:', error);
          res.status(500);
         else if (renderProps) 

            const is404 = renderProps.routes.find(r => r.status === 404) !== undefined;
        
        if (is404) 
          res.status(404).send('Not found');
         else 
            //Go on and render the freaking component...
        
    );
);

对此感到抱歉...当然我的解决方案无法自行运行,并且我错过了您实际检查此属性并进行相应渲染的正确代码段。

如您所见,我只是将“未找到”文本发送给客户端,但是,最好从 renderProps(本例中为 NoMatch)捕获要渲染的组件并进行渲染。

干杯

【讨论】:

status 参数是干什么用的?我在文档中找不到任何对它的引用。 我也从未在文档中找到它。我猜这是 2.x 文档中未完成的“高级用法”部分。但它有效,所以它一定是从那里丢失的,我一定在我不记得的地方找到了这个解决方案...... 此参数自动设置请求对象的状态。 路由器对响应对象一无所知!它将如何设置状态?在我的服务器端代码中,我必须自己设置状态。如何确定路由器是否进入 404 页面? 如果您要包括一个答案,包括整个答案是合适的。这个答案完全忽略了任何关于让它工作的真正参考。【参考方案2】:

我做了一些挖掘,这就是我们在 v4 版本中的工作方式。

<Route
  render=( staticContext ) => 
    if (staticContext) 
      staticContext.statusCode = 404
    
    return <NotFound />
  
/>

Route 组件用于访问staticContext,它有一个statusCode 属性,如果您使用StaticRouter 组件在服务器上呈现,您可以设置该属性。

服务器代码看起来像这样(带有一些 TypeScript 输入)

const currentLocation: Location = 
  pathname: req.pathname,
  search: req.search,
  hash: '',
  state: undefined


const staticRouterContext: StaticContext & StaticRouterContext = 

ReactDOMServer.renderToString(
  <StaticRouter location=currentLocation context=staticRouterContext>
  ...
  </StaticRouter>
)

if (staticRouterContext.statusCode) 
  res.status(staticRouterContext.statusCode)

注意:我认为打字有点奇怪,因为StaticRouterContext 没有来自StaticContext 接口的statusCode 属性。可能是打字错误。不过这很好用。

【讨论】:

如何使用此解决方案处理renderToNodeStream【参考方案3】:

Zen:静默网络的错误代码是什么?

我也对这个问题感到困惑。奇怪的情况是,您不会更改 HTTP 错误代码。我们认为我们应该这样做,因为调用了一个随机 URL,但为什么呢?

在 SPA(单页应用程序)中,没有网络流量,而只是切换窗格。 HTTP 错误代码位于提供新页面的标头中,而所有内容都位于名为 &lt;div&gt; 的不会重新加载新页面的标题中。需要扔掉页面,传输并渲染一个新页面以获得 404 返回码,然后在用户离开时再次发送原始页面。

而且,它只有用户。 404 错误代码或任何其他 HTTP 代码实际上是对浏览器或服务的提示。如果请求者是浏览器,则向人类提供比浏览器所能提供的更好的指示。如果请求者是爬虫,它可能会扫描&lt;h1&gt; 中的404。如果请求者将您的网站用作 API,为什么这是一件好事?

所以答案是我们出于习惯设置 HTTP 状态码。不要。

【讨论】:

即使在 SPA 中,也可能存在对 React 路由器将处理的不存在的 URL 的初始直接请求。用几十年前的标准方式来表示 URL 是否存在(状态代码),希望网站设计人员能够有效地传达它,这听起来不是一个好主意。每个网站设计师都会以不同的方式传达这一点,这会导致与任何试图理解(人类)或解析它(爬虫)的不一致。 请注意,您的论点是“那是不同的;因此它很糟糕”。您可以假设 404 是支持深度链接但不支持用于深度链接的合理 URL 的 SPA 的正确响应,并且当您可以跟踪其进入的深度链接并且您希望将正确答案发送给爬虫时。 并非如此。我只是不同意设置 HTTP 状态码只是一种习惯。它不是。这是故意做的事情,并具有特定的好处(在我的第一条评论中提到)。也就是说,在我的情况下,我解决这个问题的方法是让我的 Rails 应用程序专门指向 React 能够处理的路线。这样,其他所有内容都是具有 404 状态的常规 HTTP 响应。 “如果请求者是爬虫,它可能会扫描

中的 404” - Google 主要依赖 404 响应代码,或者当他们看到相同的 000 条路由模板时,他们会标记作为软 404。想象一下写一篇关于 404 响应的文章,并且您的 h1 包含“404”并且 Google 会自动从其索引中删除该页面。没有。

对不起,我不明白你的意思。对于 SEO,您确实需要经历不同的环节,但永远不要更改错误代码。与接收此类错误代码相关的带有 h1 文本“404”的文章将不会被查看。【参考方案4】:

为此,您还需要在服务器上运行匹配,以查看路由是否匹配。当然,如果您要这样做,您也可以进行成熟的服务器端渲染!请咨询server rendering guide。

【讨论】:

我很喜欢这个链接到 404 页面的讽刺意味 :-) 为未来的我更新了链接:reacttraining.com/react-router/web/guides/server-rendering

以上是关于如何让反应路由器响应 404 状态码?的主要内容,如果未能解决你的问题,请参考以下文章

使用反应路由器和 s-s-r 设置正确的 HTTP 状态

如何添加 404 页面以响应嵌套路由?

刷新反应应用程序,404 错误。反应路由器问题

Laravel:如何根据路由响应自定义 404 错误

如何修复 axios Next js 中的“错误:请求失败,状态码为 404”

反应路由器,在 webpack 中使用 historyApiFallback true 重新加载 404