Как разрешить реагирующему маршрутизатору ответить кодом состояния 404?

Я использую реагирующий маршрутизатор как root, и все запросы в "/" направлены на реагирующий маршрутизатор. И когда реагирующий маршрутизатор обнаружил, что URL не соответствует ни одному из определенных компонентов, он рендерится с помощью компонента NoMatch. И здесь возникает проблема, NoMatch отображается, и это то, что я хочу, но код состояния по-прежнему 200 вместо 404. И когда мои файлы CSS или JS помещены с неправильным URL-адрес реакции маршрутизатор делает то же самое, он отвечает 200! А затем страница сообщает мне, что есть проблема с типом содержимого моих ресурсов!

Итак, как я могу использовать реагирующий маршрутизатор для обработки всего в "/" и при этом заставить его правильно обрабатывать ошибки 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'
    });
  });

3 ответа

С реакции-роутером 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) и отрендерили его.

ура

Я немного покопался, вот как мы поступаем в версии 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 не имеет statusCode опора из StaticContext интерфейс. Вероятно, ошибка в наборе. Это работает просто отлично, хотя.

Zen: Какой код ошибки в тихой сети?

Я тоже озадачился этим вопросом. Странный случай, вы не меняете код ошибки HTTP. Мы думаем, что должны, потому что случайный URL был назван, но почему?

В SPA (одностраничное приложение) нет сетевого трафика, а просто переключение панелей. Код ошибки HTTP находится в заголовках для обслуживания новой страницы, в то время как весь контент находится в именованном <div> это не перезагружает новую страницу. Нужно выбросить страницу, передать и отобразить новую страницу, чтобы получить код возврата 404, а затем снова отправить исходную страницу, когда пользователь уходит.

И это только пользователь. Код ошибки 404, или любой другой код HTTP, на самом деле является подсказкой для браузера или службы. Если запрашивающий является браузером, человеку дается лучшая индикация, чем может предоставить браузер. Если запросчик является сканером, он, вероятно, сканирует 404 в <h1>"S. Если заявитель использует ваш сайт в качестве API, почему это хорошо?

Таким образом, ответ таков: мы устанавливаем коды статуса HTTP по привычке. Не.

Чтобы сделать это, вам также нужно запустить совпадение на сервере, чтобы увидеть, совпадает ли маршрут. Конечно, если вы собираетесь это сделать, вы вполне можете сделать полноценный рендеринг на стороне сервера! Обратитесь к руководству рендеринга сервера.

Другие вопросы по тегам