При использовании React для разработки нового проекта я столкнулся с ситуацией, когда страница была обновлена, и был прямой доступ к вторичному или третичному маршруту, и произошел сбой доступа, 404 или ненормальная загрузка ресурсов.В этой статье анализируется эта проблема и кратко излагается решение.
задний план
При использовании webpack-dev-server в качестве локального сервера разработки необходимо просто использоватьwebpack-dev-server
Команду можно запустить, но когда проект находится в следующих двух ситуациях, часто требуются вложенные маршруты и маршруты асинхронной загрузки:
- Мы используем react-router, библиотеку маршрутизации, для построения маршрутизации одностраничных приложений;
- использовать
html-webpack-plugin
Плагин будет динамически загружать js<script>
Теги внедряются в html-документы;
В это время посетитеlocalhost:9090
Можно загружать файлы, такие как страницы и js, как обычно, но когда нам нужно получить доступ к вторичным или даже третичным маршрутам или обновить страницу, напримерlocalhost:9090/posts/92
, могут возникнуть две ситуации:
- Не удалось загрузить страницу, вернуться
Cannot Get(404)
; - Сервис отвечает, но не возвращает html-файл, обработанный вебпаком, в результате чего невозможно загрузить js-ресурсы.Второй случай показан на рисунке:
Итак, как мы справляемся с этим, чтобы получить к нему нормальный доступ, и как мы маршрутизируем каждую страницу? Блогер отслеживает источник, находит конфигурацию документа и решает проблему.Эта статья представляет собой краткое изложение всего процесса решения проблемы.
анализировать проблему
После обнаружения проблемы мы начнем анализировать и решать проблему.Мы считаем, что проблема обычно вызвана двумя причинами:
- конфигурация внешней маршрутизации react-router;
- конфигурация сервиса 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 здесь.Блогер перечитал ее несколько раз, прежде чем ясно увидел проблему.Здесь есть две ситуации:
- без модификации
output.publicPath
, то есть в конфигурационном файле webpack не объявлено значение, которое установлено по умолчанию; - уже настроен
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 settinghistoryApiFallback: 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 thehistoryApiFallback.index
optionЕсли вы измените файл конфигурации webpack
output.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