Реакция маршрутизации способна обрабатывать разные URL-адреса, но tomcat возвращает 404 недоступных ресурсов

Я новичок в reactjs, и у меня есть небольшой проект в reactjs, чтобы играть и изучать его. Мне нужно иметь тип заголовков, которые будут показаны на основе URL-адресов. Итак, это мой index.js, который обрабатывает маршрутизацию:

 const history = useRouterHistory(createHistory)({
     basename: '/test'
})
class Tj extends React.Component {

render() {

    return (
        <Router history={history}>
            <Route path={"/"} component={Bridge} >
                <IndexRoute component={Home} />
                <Route path={"user"} component={T} />
                <Route path={"home"} component={Home} />
            </Route>
            <Route path={"/t/"} component={Bridge2} >
                <IndexRoute component={T} />
                <Route path={"contact"} component={Home} />
            </Route>
        </Router>
    );
}
}
render(
<Provider store={store}>
    <Tj/>
</Provider>,
window.document.getElementById('mainContainer'));

Как вы можете видеть, я использую test в качестве корневого каталога и на основе ввода пользователем для url. Я решаю, какой заголовок использовать. Также здесь Bridge2.js:

export class Bridge2 extends React.Component {
render() {

    return (
        <div>
            <div className="row">
                <Header2/>
            </div>
            <div className="row">
                {this.props.children}
            </div>
        </div>
    );
}
}

и Bridge.js:

export class Bridge extends React.Component {
render() {
  //  alert(this.props.children.type);
    var Content;

    if(this.props.children.type){
    Content=<div>
        <div className="row">
            <Header/>
        </div>
        <div className="row">
            {this.props.children}
        </div>
    </div>;
    }
    else{
        Content=<div>
            <div className="row">
                <Header/>
            </div>
            <div className="row">
                {this.props.children}
            </div>
        </div>;
    }
    return (
        Content
    );
}
}

Когда я запускаю это в сервере webpack dev, все прекрасно работает. Например, когда я использую http://localhost:3003/test/, загружается файл bridge.js, и если я запускаю http://localhost:3003/test/t/, то загружается файл bridge2.js, который ожидается.

Однако, поскольку сервер веб-пакетов dev не является производственным сервером, я использую tomcat, и на данный момент я использую проект веб-приложения eclipse, и я скопировал файл bundle.js и index.html там. Теперь проблема в том, что когда я запускаю сервер tomcat, он способен распознать и показать этот путь:

http://localhost:8080/test/, но когда для http://localhost:8080/test/t/ получаем:

Состояние HTTP 404 -/test/t/

который в основном говорит, что файл ресурсов недоступен. Насколько я понимаю, это не проблема в кодировании, поскольку маршрутизация отлично работает в сервере веб-пакетов dev, но когда дело доходит до tomcat, кажется, что реакция маршрутизации не в состоянии справиться с этим. Что-то не так с тем, что я делаю? Выполняется таким образом вообще? Может ли кто-нибудь помочь?

Ответ 1

Сначала вы должны знать о следующих отличиях при использовании реактивного маршрутизатора.

Когда вы вводите "localhost: 3003/test/" в своем браузере, он будет запрашивать сервер, а затем он получит /test/index.html, js bundle, css,...

После этого всякий раз, когда вы нажимаете внутреннюю ссылку (например, "localhost: 3003/test/t/" ), ваш браузер больше не будет запрашивать сервер.

React-router решит эту клиентскую сторону, повторно отобразит части страницы и обновит адресную строку браузера (используя html5 pushstate), не запуская другой запрос сервера.

Когда вы вводите "localhost: 3003/test/t/" непосредственно в адресной строке, ваш браузер запрашивает сервер, а Tomcat не имеет /test/t/index.html или так, и он возвращает 404, Это потому, что Tomcat ничего не знает о реакции-редукции или javascript.

Способ справиться с этим состоит в том, чтобы настроить 404 ошибки для перехода в /test/index.html. Вероятно, как ваш сервер веб-сервера devp настроен по умолчанию.

Есть много примеров этого на apache, если у вас есть один перед нашим Tomcat. Найдите "html5 pushstate apache config".

Вот один пример

httpd.conf

...
<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteBase /
    RewriteRule ^index\.html$ - [L]
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule . /index.html [L]
 </IfModule>
...

Если вы используете только tomcat, вы можете попытаться указать это в файле web.xml внутри вашего военного файла.

...
<error-page>
    <error-code>404</error-code>
    <location>/index.html</location>
</error-page>
...

Обратите внимание, что это не проблема с конкретным маршрутом, каждое приложение, использующее html5 pushstate, должно как-то справиться с этим. Однако серверы Javascript могут справиться с этим более легко.

Ответ 2

Tomcat 8 и выше имеет простое встроенное решение для этого. Вам не нужно ставить его позади Apache, чтобы справиться с этим, или переключиться на хэш-маршрутизацию, или взломать страницу перенаправления, чтобы вернуться в другое место на вашем собственном сервере...

Используйте Tomcat Rewrite

Он работает для любой среды приложения с одной страницей, которая имеет UI-маршрутизацию, например React, Angular, ExtJS и т.д.


В двух словах:

1) Добавьте RewriteValve в /tomcat/webapps/{your-web-app-directory}/META-INF/context.xml

<?xml version="1.0" encoding="UTF-8"?>
<Context>  
  <Valve className="org.apache.catalina.valves.rewrite.RewriteValve" />
  ... your other context items
</Context>

2) Создайте файл с именем://tomcat/webapps/{your-web-app-directory}/WEB-INF/rewrite.config а затем добавьте правила перезаписи для любых путей, которые вы хотите указать на своей странице индекса:

RewriteRule ^/user(.*)$    /index.html [L]
RewriteRule ^/home(.*)$    /index.html [L]
RewriteRule ^/contact(.*)$ /index.html [L]

Эти правила сообщают Tomcat отправлять все запросы с этими тремя именованными путями прямо в index.html.

3) Перезапустите Tomcat

Правила могут стать более изящными, как отправка всех запросов в index.html, за исключением определенного пути, что полезно для вызовов /api которые должны идти куда-то, кроме index.html. Ссылка выше охватывает дополнительные примеры использования Tomcat Rewrite.

Ответ 3

Мое решение подобно обходному пути для JSP-движков (например, Tomcat), но отлично работает с минимальным кодом.

Я создал "index.jsp" параллельно "index.html" (в корневой папке содержимого) со следующим кодом:

index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@include file="index.html"%>

Я настроил все URL-адреса для перенаправления на этот JSP в web.xml

web.xml

<servlet>
    <servlet-name>index</servlet-name>
    <jsp-file>index.jsp</jsp-file>
</servlet>
<servlet-mapping>
    <servlet-name>index</servlet-name>
    <url-pattern>/*</url-pattern>
</servlet-mapping>

Теперь любой URL-адрес, запрошенный Tomcat, будет внутренне перенаправлен на index.jsp, что эффективно index.html. После загрузки адаптера в браузере он заботится о рендеринге правильного компонента и последующих запросов.

Ответ 4

У меня такая же проблема, что и маршрутизация не работает. Если 404 не перенаправляет и не загружает проблему index.html. Я попробовал несколько способов и, наконец, нашел решение, которое исправило мою проблему.

Это работало для меня на Tomcat 8

inside ROOT folder of Tomcat make a new folder WEB-INF and create web.xml 

Вы можете это сделать

sudo gedit /opt/tomcat/webapps/ROOT/WEB-INF/web.xml

вставьте ниже в web.xml

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
    <display-name>your_display_name</display-name>

    <error-page>
        <error-code>404</error-code>
        <location>/index.html</location>
    </error-page>

</web-app>

Перезапустите Tomcat. Это устранило проблему маршрутизации для меня. Надеюсь, это поможет кому-то, кого я думаю. благодаря

Ответ 5

Пока я не знаком с Tomcat, наиболее вероятно, что ваш сервер ищет файл /test/t или /test/t/index.html, и поскольку он не существует, он возвращает ошибку 404.

Когда вы используете историю браузера, вам необходимо иметь сервер, который может обрабатывать маршрутизацию. Обычно это будет шаблон подстановочного знака (*), который возвращает ваш файл index.html (который, в свою очередь, вернет ваши вложенные js, а также любые другие статические файлы, включенные в индексный файл).

Одним из решений является переход на использование хэш-маршрутизатора. Если вы не можете выполнять маршрутизацию на сервере (особенно это важно для людей, которые размещают статический контент), то необходима хэш-маршрутизация. Однако, поскольку вы используете сервер, вы должны иметь возможность настроить маршрутизацию, которая позволит вам использовать маршрутизатор браузера.

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

  • Все запросы на статические файлы должны регулярно выполняться.
  • Все остальные запросы /test/* (где * - любой URL-адрес) должны служить вашему файлу index.html.

Ответ 6

Я думаю, что ответ на вопрос ОП должен касаться также доступа к статическим ресурсам через сервлет по умолчанию.

В моем понимании проблема возникает в приложениях с множественным просмотром React, где Router используется для изменения URL-адреса страницы, чтобы отразить состояние приложения. Это хорошо, но если вы перезагрузите страницу случайно, вы получите 404, так как не будет никакого ресурса, соответствующего измененному URL. Это также означает, что такие измененные URL-адреса не могут быть помечены как прямой доступ к различным представлениям приложений. Если мы не получим небольшую помощь со стороны сервера.

В зависимости от того, как обрабатывается доступ к статическим ресурсам или выбранной реализации (фильтр, сервлет или даже JSP), существует больше решений, но основная идея состоит в том, чтобы обслуживать основной файл HTML приложения для всех Маршрутов, определенных в Реагировании.

Предположим, что у вас есть два маршрута React Routes, определенные в вашем приложении:

<Route path={"view1"} component={View1} />
<Route path={"view2"} component={View2} />

Вы можете создать RouterServlet для пересылки запросов в /view1 или /view2 обратно в корневой контекст (/), предположив, что вы сопоставили приложение здесь.

void doGet(HttpServletRequest request, HttpServletResponse response) 
        throws ServletException, IOException 
{
    request.getServletContext().getRequestDispatcher("/").forward(request, response);
}

Вы можете настроить его следующим образом:

<servlet>
    <servlet-name>RouterServlet</servlet-name>
    <servlet-class>package.RouterServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>RouterServlet</servlet-name>
    <url-pattern>/view1/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>RouterServlet</servlet-name>
    <url-pattern>/view2/*</url-pattern>
</servlet-mapping>

Ответ 7

В моем случае я хотел простое решение, как при создании страницы с ошибкой клиента. Однако это решение все еще устанавливает код состояния 404 который нежелателен.

Поэтому я использую небольшой JSP файл, который установит код состояния на 200 прежде чем выводить SPA index.html.

Я надеюсь, что это поможет кому-то еще, ищущему простое решение, не возвращая статус 404.

web.xml

<error-page>
    <error-code>404</error-code>
    <location>/spa.jsp</location>
</error-page>

spa.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%><%
    response.setStatus(200);
%><%@include file="./dashboard/index.html"%>

Ответ 8

Для версий Tomcat ниже 8. Вы можете просто добавить web.xml и направить 404 в index.html.

webapps/[my-app-name]/WEB-INF/web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
          http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
          version="2.4">

  <display-name>my-app-name</display-name>

  <error-page>
    <error-code>404</error-code>
    <location>/index.html</location>
  </error-page>

</web-app>