react-router browserHistory обновить страницу 404 решение проблемы

внешний интерфейс сервер React.js Webpack

При использовании React для разработки нового проекта я столкнулся с ситуацией, когда страница была обновлена, и был прямой доступ к вторичному или третичному маршруту, и произошел сбой доступа, 404 или ненормальная загрузка ресурсов.В этой статье анализируется эта проблема и кратко излагается решение.

Посмотреть личный блог

задний план

При использовании webpack-dev-server в качестве локального сервера разработки необходимо просто использоватьwebpack-dev-serverКоманду можно запустить, но когда проект находится в следующих двух ситуациях, часто требуются вложенные маршруты и маршруты асинхронной загрузки:

  1. Мы используем react-router, библиотеку маршрутизации, для построения маршрутизации одностраничных приложений;
  2. использоватьhtml-webpack-pluginПлагин будет динамически загружать js<script>Теги внедряются в html-документы;

В это время посетитеlocalhost:9090Можно загружать файлы, такие как страницы и js, как обычно, но когда нам нужно получить доступ к вторичным или даже третичным маршрутам или обновить страницу, напримерlocalhost:9090/posts/92, могут возникнуть две ситуации:

  1. Не удалось загрузить страницу, вернутьсяCannot Get(404);
  2. Сервис отвечает, но не возвращает html-файл, обработанный вебпаком, в результате чего невозможно загрузить js-ресурсы.Второй случай показан на рисунке:

react-router-browser-history

Итак, как мы справляемся с этим, чтобы получить к нему нормальный доступ, и как мы маршрутизируем каждую страницу? Блогер отслеживает источник, находит конфигурацию документа и решает проблему.Эта статья представляет собой краткое изложение всего процесса решения проблемы.

анализировать проблему

После обнаружения проблемы мы начнем анализировать и решать проблему.Мы считаем, что проблема обычно вызвана двумя причинами:

  1. конфигурация внешней маршрутизации react-router;
  2. конфигурация сервиса webpack-dev-server;

react-router

Поскольку интерфейсную маршрутизацию легче определить, ее удобнее анализировать и она лучше знакома с react-router, поэтому сначала проверьте соответствующую информацию о конфигурации библиотеки маршрутизации react-router и обнаружил, что в документе упоминается использованиеbrowserHistory, будет создан настоящий URL-адрес, обрабатывающий исходный/С запросом проблем нет, но когда вы обновляете страницу или напрямую обращаетесь к URL-адресу после перехода по маршруту, вы обнаружите, что на него невозможно правильно ответить.Посмотреть справочную документацию, документ также предоставляет несколько решений по настройке сервера:

Node

const express = require('express')
const path = require('path')
const port = process.env.PORT || 8080
const app = express()

// 通常用于加载静态资源
app.use(express.static(__dirname + '/public'))

// 在你应用 JavaScript 文件中包含了一个 script 标签
// 的 index.html 中处理任何一个 route
app.get('*', function (request, response){
  response.sendFile(path.resolve(__dirname, 'public', 'index.html'))
})

app.listen(port)
console.log("server started on port " + port)

Подстановочные знаки необходимы при использовании Node в качестве службы*Слушайте все запросы и возвращайте целевой HTML-документ (html, ссылающийся на ресурсы js).

Nginx

Если вы используете сервер nginx, вам просто нужно использоватьtry_filesинструкция:

server {
  ...
  location / {
    try_files $uri /index.html
  }
}

Apache

Если вы используете сервер Apache, вам необходимо создать в корневом каталоге проекта.htaccessфайл, файл содержит следующее:

RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]

Ниже приведена конфигурация для сервера.К сожалению, мы еще не представили соответствующий сервер, а только используем встроенный сервис webpack-dev-server, но мы обнаружили проблему, то есть запрос маршрутизации не может соответствовать возвращенный html-документ, так что найдите время перейти к документации webpack-dev-server, чтобы найти решение.

webpack-dev-server

Я должен пожаловаться на официальную документацию webpack-dev-server здесь.Блогер перечитал ее несколько раз, прежде чем ясно увидел проблему.Здесь есть две ситуации:

  1. без модификацииoutput.publicPath, то есть в конфигурационном файле webpack не объявлено значение, которое установлено по умолчанию;
  2. уже настроенoutput.publicPathявляется пользовательским значением;

Нажмите здесь, чтобы просмотреть документ

По умолчанию

По умолчанию без измененийoutput.publicPathзначение, просто нужно установить webpack-dev-serverhistoryApiFallbackКонфигурация:

devServer: {
  historyApiFallback: true
}

If you are using the HTML5 history API you probably need to serve your index.html in place of 404 responses, which can be done by setting historyApiFallback: true

Если ваше приложение использует API истории HTML5, вам может понадобиться использоватьindex.htmlЧтобы ответить на 404 или проблемный запрос, просто установите ghistoryApiFallback: trueТолько что

пользовательское значение

However, if you have modified output.publicPath in your Webpack configuration, you need to specify the URL to redirect to. This is done using the historyApiFallback.index option

Если вы измените файл конфигурации webpackoutput.publicPathзначение, то нужно объявить перенаправление запроса, настроитьhistoryApiFallback.indexстоимость.

// output.publicPath: '/assets/'
historyApiFallback: {
  index: '/assets/'
}

Proxy

Я обнаружил, что использование вышеуказанных методов не полностью решило мою проблему, и всегда будет ненормальный ответ на запрос маршрутизации, поэтому блогер продолжил искать лучшее решение:

Нажмите здесь, чтобы просмотреть документ

The proxy can be optionally bypassed based on the return from a function. The function can inspect the HTTP request, response, and any given proxy options. It must return either false or a URL path that will be served instead of continuing to proxy the request.

Прокси предоставляет способ ответить на запрос через возвращаемое значение функции и выполняет различную обработку для разных запросов.Параметры функции получают HTTP-запрос и тело ответа, а также объект конфигурации прокси.Эта функция должна возвращать false или URL-путь, чтобы указать, как продолжить обработку запроса. При возврате URL-адреса исходный запрос будет проксирован с этим запросом URL-пути.

proxy: {
  '/': {
    target: 'https://api.example.com',
    secure: false,
    bypass: function(req, res, proxyOptions) {
      if (req.headers.accept.indexOf('html') !== -1) {
        console.log('Skipping proxy for browser request.');
        return '/index.html';
      }
    }
  }
}

Настроено, как указано выше, вы можете контролироватьhttps://api.example.comпод доменом/Запрос в начале (эквивалентно всем запросам), а затем судить о заголовке запросаacceptСодержит ли полеhtml, если включены, прокси-запросы к/index.html, который затем вернет документ index.html в браузер.

Решать проблему

Объединение вышеуказанных решений, потому что конфигурация WebPack модифицированаoutput.publicPathдля/assets/, поэтому блогер решил проблему с помощью метода прокси-сервера webpack-dev-server:

const PUBLICPATH = '/assets/'
...
proxy: {
  '/': {
    bypass: function (req, res, proxyOptions) {
      console.log('Skipping proxy for browser request.')
      return `${PUBLICPATH}/index.html`
    }
  }
}

Слушайте все внешние маршруты и возвращайтесь напрямую${PUBLICPATH}/index.html,PUBLICPATHустановленoutput.publicPathстоимость.

Кроме того, блогеры всегда по привычке заявляют, что хоть это свойство и не задано, ожидаемый эффект доступа можно встретить:

historyApiFallback: true