¿Cómo configurar correctamente Apache en una aplicación SPA React que reside en un subdirectorio que usa URL anidadas creadas a partir de React Router?

Jul 04 2020

Tengo mi sitio web alojado en un subdirectorio, por ejemplo, http: // mywebsite / admin, donde / admin es el subdirectorio

Tengo mi aplicación de reacción (creación de producción de la aplicación de reacción) cargada en el subdirectorio / admin. También estoy usando react-router v4 BrowserRouter para realizar un enrutamiento simple del lado del cliente. A continuación se muestran algunos fragmentos relevantes en mi aplicación de reacción:

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/App';
import { BrowserRouter } from 'react-router-dom';

import './css/custom.css';

ReactDOM.render(<BrowserRouter basename="/admin"><App /></BrowserRouter>, document.getElementById("root"));

dentro de la función de renderización App.jsx

<Route
    path='/students'
    render={(props) =>
        <Students
            {...props}
        />
    }
/>

<Route
    path='/teachers'
    render={(props) =>
        <Teachers
            {...props}
        />
    }
/>

Todo está bien y funcionando al navegar por el sitio, incluidas las URL anidadas que son principalmente, como ha visto en los fragmentos, /admin/students& /admin/teachers.

El problema principal: cuando estoy en la /admin/teachersruta y actualizo la página , la página no carga nada. Refrescante funciona solo cuando estoy en /adminruta. Pero no cuando es /admin/teachersni /admin/students.

Esta no es la primera vez que construyo un SPA usando react-router v4 alojado en el servidor Apache. He reutilizado el .htaccess que tenía en mi proyecto anterior. Este .htaccess también reside en el /adminsubdirectorio. A continuación se muestra .htaccess:

.htaccess

RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.html?path=$1 [NC,L,QSA]

Esto enruta todas las solicitudes al index.html creado por la compilación de producción create-react-app. Sin embargo, según mis investigaciones, este tipo de configuración solo funciona en un proyecto que no está en un subdirectorio y no usa URL anidadas.

Tenga en cuenta que .htaccessahora tengo 2 . Uno en la raíz y otro en el /adminsubdirectorio. Ambos contienen los mismos .htaccesscódigos . La razón de esto es que tengo otro SPA ejecutándose en el directorio raíz.

¿Qué me estoy perdiendo?

¿Cómo configurar correctamente Apache en una aplicación SPA React que reside en un subdirectorio que usa URL anidadas creadas a partir de React Router?

Respuestas

2 MrWhite Jul 17 2020 at 00:05

Abordar principalmente la respuesta del OP , más algunas otras notas ...

Aquí es donde cometí un error:

Tenga en cuenta que ahora tengo 2 .htaccess. Uno en root y otro en el subdirectorio / admin. Ambos contienen los mismos códigos .htaccess. La razón de esto es que tengo otro SPA ejecutándose en el directorio raíz.

Esto no fue necesariamente un "error", solo debe asegurarse de que está utilizando las directivas correctas. De hecho, .htaccesspodría ser preferible mantener los dos archivos separados si se pretende que sean SPA completamente separados.

Para tener dos .htaccessarchivos separados, idénticos, los puntos importantes son:

  • Haga que la cadena de sustitución sea relativa , es decir. sin prefijo de barra.
  • No incluya una RewriteBasedirectiva. (Lo que anularía el prefijo de directorio).

Cuando la cadena de RewriteRule sustitución es una ruta relativa , el prefijo del directorio (es decir, la ubicación del .htaccessarchivo) se vuelve a agregar al final del proceso de reescritura.

Entonces, ambos /.htaccessy /admin/.htaccesscontendrían directivas idénticas:

RewriteEngine on
RewriteRule ^index\.html$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule (.+) index.html?path=$1 [L,QSA]

SIN EMBARGO, una pequeña diferencia con esta solución y la solución del OP es que la admin/parte de la ruta URL no se pasa al pathparámetro URL. Puede codificar esto si es necesario. p.ej. index.html?path=admin/$1. O tenga en cuenta esto en su guión.

La primera RewriteRulees solo una optimización menor que evita más verificaciones del sistema de archivos después de que la solicitud ya se haya reescrito index.html.

Tenga en cuenta que cambié (.*)(0 o más) a (.+)(1 o más). Esto evita la verificación de directorio adicional al solicitar el directorio raíz. es decir. example.com/y example.com/admin/. No está reescribiendo estas solicitudes, sino que depende de que DirectoryIndex index.htmlse configure adecuadamente; esta es la configuración predeterminada en la configuración del servidor.

Dado que la cadena de sustitución ( index.php?page=$1) es relativa, cuando esté en la raíz del documento se reescribirá efectivamente /index.phpy cuando /admin/.htaccessesté en ella se reescribirá efectivamente /admin/index.php.

Tenga en cuenta que las directivas mod_rewrite /admin/.htaccessanulan completamente las directivas mod_rewrite en el .htaccessarchivo principal , ya que las directivas mod_rewrite no se heredan de forma predeterminada (a diferencia de otros módulos).


Alternativamente, para evitar la repetición, mientras mantiene dos .htaccessarchivos separados , puede habilitar la herencia mod_rewrite en el /admin/.htaccessarchivo. Por ejemplo...

En el /.htaccessarchivo raíz :

RewriteEngine on
RewriteRule ^index\.html$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule (.+) index.html?path=$1 [L,QSA]

Entonces, en su lugar /admin/.htaccesstendrías lo siguiente:

RewriteEngine On
RewriteOptions Inherit

Esto hereda las directivas mod_rewrite padre como si se hubieran copiado literalmente en el lugar del /admin/.htaccessarchivo.

Sin embargo, esto agrega una capa adicional de complejidad. Además de que el SPA /adminahora depende del .htaccessarchivo raíz , ahora debe tener cuidado de no agregar ninguna directiva de ruptura al .htaccessarchivo raíz .


Aparte:

RewriteCond %{REQUEST_URI} admin
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) admin/index.html?path=$1 [QSA,L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule (.*) index.html?path=$1 [QSA,L]

La primera condición que busca "admin" en la ruta de la URL (por cierto, esto busca "admin" en cualquier parte de la ruta de la URL, lo cual no es estrictamente correcto) no es necesaria; la verificación se puede realizar de manera más óptima en el RewriteRuledirectiva en sí. Por ejemplo:

RewriteRule ^(admin/.*) admin/index.html?path=$1 [QSA,L]

Estas dos reglas se pueden combinar en una si se desea, posiblemente a expensas de cierta claridad. Por ejemplo:

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(admin/)?.* $1index.html?path=$0 [QSA,L]

La $1referencia inversa entonces contiene el prefijo de ruta opcional, ya sea admin/o nada . Y $0contiene el partido completo.

2 eric Jul 14 2020 at 06:35

Aquí es donde cometí un error:

Tenga en cuenta que ahora tengo 2 .htaccess. Uno en root y otro en el subdirectorio / admin. Ambos contienen los mismos códigos .htaccess. La razón de esto es que tengo otro SPA ejecutándose en el directorio raíz.

Simplemente ajustando mi raíz .htaccess y eliminando el .htaccessque estaba dentro del subdirectorio / admin solucionó el problema principal descrito en mi pregunta.

Raíz .htaccess :

RewriteCond %{REQUEST_URI} admin
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) admin/index.html?path=$1 [QSA,L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule (.*) index.html?path=$1 [QSA,L]
1 DanieleRicci Jul 09 2020 at 05:46

De hecho, no conozco la respuesta a su problema, pero puedo sugerirle que juegue con la Locationdirectiva; algo como

<Location "/admin">
  RewriteEngine on
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteRule ^(.*)$ /admin/index.html?path=$1 [NC,L,QSA]
</Location>

Espero que esto ayude.