web-dev-qa-db-fra.com

réactiver le routage est capable de gérer différents chemins d'URL mais Tomcat renvoie 404 ressources non disponibles.

Je suis nouveau dans reactjs et j'ai un petit projet dans reactjs pour jouer avec et apprendre. Je dois avoir à taper les en-têtes qui seront affichés en fonction des chemins d’URL. Voici donc mon index.js qui gère le routage:

 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'));

Comme vous pouvez le constater, j'utilise test en tant que répertoire racine et, en fonction des entrées de l'utilisateur pour l'URL, je décide quel en-tête dois-je utiliser? Aussi voici Bridge2.js:

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

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

et 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
    );
}
}

Quand je lance ceci dans WebPack dev Server, tout fonctionne correctement. Par exemple, lorsque j'utilise http://localhost:3003/test/ bridge.js est chargé et si je lance http://localhost:3003/test/t/ bridge2.js, il est chargé, ce qui est attendu.

Cependant, étant donné que le serveur de pack Web n'est pas un serveur de production, j'utilise Tomcat. Pour l'instant, j'utilise le projet d'application Web Eclipse et j'ai copié mon fichier bundle.js et mon index.html. Maintenant, le problème est que lorsque je lance le serveur Tomcat, il est capable de reconnaître et d’afficher ce chemin correctement: 

http://localhost:8080/test/ mais quand pour http://localhost:8080/test/t/ je reçois:

Statut HTTP 404 -/test/t /

qui dit essentiellement que le fichier de ressources n'est pas disponible. En ce qui concerne ce que j’observe, ce n’est pas un problème de codage puisque le routage fonctionne très bien sur le serveur de Web pack dev, mais s’agissant de Tomcat, il semble que le routage réactif n’est pas capable de le gérer. Y a-t-il un problème avec ce que je fais? Est-ce faisable de cette façon? Quelqu'un peut-il aider?

16
Hamed Minaee

Tout d'abord, vous devez connaître les différences suivantes lors de l'utilisation de react-router.

Lorsque vous entrez "localhost: 3003/test /" dans votre navigateur, il demande le serveur, puis il recevra /test/index.html, le bundle js, css, ...

Après cela, chaque fois que vous cliquez sur un lien interne (par exemple, 'localhost: 3003/test/t /'), votre navigateur ne demandera plus le serveur. 

React-router résoudra ce côté client, restitue des parties de la page et met à jour la barre d'adresse du navigateur (à l'aide de html5 pushstate), sans déclencher une autre demande de serveur.

Lorsque vous entrez "localhost: 3003/test/t /" directement dans la barre d'adresse, votre navigateur demande le serveur, et Tomcat ne dispose pas du fichier /test/t/index.html, et renvoie 404 . C'est parce que Tomcat ne sait rien de react-redux ni de javascript.

Une façon de gérer cela consiste à configurer les erreurs 404 afin qu'elles soient transférées vers /test/index.html. C'est probablement ainsi que votre serveur webpack dev est configuré par défaut.

Il existe de nombreux exemples de ce type d'opération sur Apache, si vous en avez un devant notre Tomcat. Recherchez "html5 pushstate Apache config".

Voici un exemple 

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>
...

Si vous utilisez uniquement Tomcat, vous pouvez essayer de spécifier cela dans le fichier web.xml, dans votre fichier war.

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

Notez qu'il ne s'agit pas d'un problème spécifique à la réaction, toutes les applications utilisant html5 pushstate doivent le gérer d'une manière ou d'une autre. Les serveurs Javascript peuvent gérer cela de manière plus transparente cependant. 

31
Rafael Z.

Ma solution s'apparente à une solution de contournement pour les moteurs JSP (Tomcat, par exemple), mais elle fonctionne parfaitement avec un code minimal.

J'ai créé un "index.jsp" parallèle à "index.html" (dans le dossier racine du contenu) avec le code suivant:

index.jsp

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

J'ai configuré toutes les URL pour rediriger vers ce JSP dans 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>

Désormais, toute URL demandée à Tomcat sera redirigée en interne vers index.jsp, qui est effectivement index.html. Une fois que le routeur réagit dans le navigateur, il se charge de restituer le bon composant et les requêtes suivantes.

5
Bipul

Tomcat a une solution intégrée simple pour cela . Vous n'avez pas besoin de le mettre derrière Apache, ni de passer au routage par hachage, ni de pirater une page de redirection pour revenir à un emplacement différent sur votre propre serveur ...

Cela devrait fonctionner pour tout framework d'application simple page ayant un routage d'interface utilisateur comme React, Angular, ExtJS, etc.


En un mot:

1) Ajoutez une RewriteValve à 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) Ajouter des règles de réécriture pour tous les chemins à /webapps/{your-web-app-directory}/WEB-INF/rewrite.config

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

Ces règles simples indiquent à Tomcat qu'il doit envoyer toutes les demandes avec ces trois chemins nommés directement à index.html. 

Mais les règles peuvent devenir beaucoup plus sophistiquées, comme envoyer toutes les requêtes à index.html sauf un certain chemin, par exemple. pour les appels /api qui doivent aller ailleurs. Le texte lié ci-dessus couvre tous les détails.

2
Geronimo

Je pense qu'une réponse à la question du PO devrait également concerner l'accès aux ressources statiques via le servlet par défaut.

À ma connaissance, le problème apparaît dans les applications React multi-vues dans lesquelles un routeur est utilisé pour modifier l'URL de la page afin de refléter l'état de l'application. C'est bien, mais si vous rechargez la page par accident, vous obtenez 404, car aucune ressource ne correspond à l'URL modifiée. Cela signifie également que de telles URL modifiées ne peuvent pas être marquées comme un accès direct à différentes vues d'application. Sauf si nous avons un peu d'aide du côté serveur.

Plusieurs solutions sont possibles en fonction de la gestion de l'accès aux ressources statiques ou de l'implémentation choisie (filtre, servlet ou même JSP), mais l'idée de base est de servir le fichier HTML principal de l'application pour chaque itinéraire défini dans React.

En supposant que vous ayez deux itinéraires de réaction définis dans votre application:

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

Vous pouvez créer un RouterServlet pour renvoyer les demandes à/view1 ou/view2 à la racine du contexte (/), en supposant que vous avez mappé l'application ici.

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

Vous pouvez le configurer comme ceci:

<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>
1
arpadf

Bien que je ne connaisse pas Tomcat, ce qui se passe probablement, c’est que votre serveur recherche un fichier /test/t ou /test/t/index.html et qu’aucun n’existe, il renvoie une erreur 404.

Lorsque vous utilisez un historique de navigateur, vous devez disposer d'un serveur capable de gérer le routage. En général, il s’agit d’un itinéraire générique (*) qui renvoie votre fichier index.html (qui à son tour renverra vos fichiers js groupés ainsi que tous les autres fichiers statiques inclus dans le fichier d’index).

Une solution consiste à utiliser un routeur de hachage. Si vous ne parvenez pas à effectuer le routage sur le serveur (particulièrement utile pour les personnes hébergeant du contenu statique), le routage par hachage est nécessaire. Cependant, étant donné que vous utilisez un serveur, vous devriez pouvoir configurer un routage qui vous permettra d'utiliser un routeur de navigateur.

Comme je l'ai déjà dit, je ne connais pas bien Tomcat, je vais donc décrire ce que devrait être la configuration.

  1. Toutes les demandes de fichiers statiques doivent être servies régulièrement.
  2. Toutes les autres demandes adressées à /test/* (où * est une URL) doivent servir votre fichier index.html.
1
Paul S

J'ai le même problème de routage ne fonctionne pas. Si 404 ne redirige pas et ne charge pas le problème index.html. J'ai essayé plusieurs façons et j'ai finalement trouvé une solution qui résout mon problème.

Cela a fonctionné pour moi sur Tomcat 8

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

Vous pouvez le faire en 

Sudo gedit /opt/Tomcat/webapps/ROOT/WEB-INF/web.xml

collez le ci-dessous dans le 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>

Redémarrez le Tomcat. Cela corrigeait le problème de routage pour moi ... Je pense que cela aiderait quelqu'un. Merci

1
Shinto Joseph

Dans mon cas, je voulais une solution simple comme créer une page d'erreur client. Cependant, cette solution définit toujours un code d'état 404 qui n'est pas souhaité.

J'utilise donc un petit fichier jsp qui définit le code d'état sur 200 avant de générer le index.html du SPA.

J'espère que cela aidera quelqu'un d'autre à la recherche d'une solution simple sans renvoyer le statut 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"%>
0
Clayton Bell