Come configurare correttamente Apache su un'app SPA React che risiede in una sottodirectory che utilizza URL nidificati creati da React Router?

Jul 04 2020

Ho il mio sito web ospitato in una sottodirectory, ad esempio http: // mywebsite / admin, dove / admin è la sottodirectory

Ho caricato la mia app React (build di produzione create-React-App) nella sottodirectory / admin. Sto anche usando il browserRouter di react-router v4 per eseguire un semplice instradamento lato client. Di seguito sono riportati alcuni frammenti pertinenti sulla mia app REATT:

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

all'interno della funzione di rendering di App.jsx

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

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

Tutto va bene e funziona durante la navigazione nel sito, inclusi gli URL annidati che sono principalmente, come hai visto negli snippet, /admin/students& /admin/teachers.

Il problema principale: quando sono sul /admin/teacherspercorso e aggiorno la pagina , la pagina non carica nulla. L'aggiornamento funziona solo quando sono in /adminviaggio. Ma non quando è /admin/teachers/admin/students.

Non è la prima volta che costruisco una SPA utilizzando il router reattivo v4 ospitato sul server Apache. Ho riutilizzato il file .htaccess che ho nel mio progetto precedente. Anche questo .htaccess risiede nella /adminsottodirectory. Di seguito è il .htaccess:

.htaccess

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

Questo indirizza tutte le richieste al file index.html creato dalla build di produzione create-react-app. Tuttavia, in base alle mie indagini, questo tipo di configurazione funziona solo su un progetto che non si trova in una sottodirectory e non utilizza URL nidificati.

Nota che ora ne ho 2 .htaccess. Uno su root e un altro nella /adminsottodirectory. Entrambi contengono gli stessi .htaccesscodici . Il motivo è che ho un altro SPA in esecuzione nella directory principale.

Cosa mi manca?

Come configurare correttamente Apache su un'app SPA React che risiede in una sottodirectory che utilizza URL nidificati creati da React Router?

Risposte

2 MrWhite Jul 17 2020 at 00:05

Affrontando principalmente la risposta dell'OP , più alcune altre note ...

Qui è dove ho commesso un errore:

Nota che ora ho 2 .htaccess. Uno su root e un altro nella sottodirectory / admin. Entrambi contengono gli stessi codici .htaccess. Il motivo è che ho un altro SPA in esecuzione nella directory principale.

Questo non è stato necessariamente un "errore": avresti solo bisogno di assicurarti di utilizzare le direttive corrette. In effetti, tenere .htaccessseparati i due file potrebbe essere preferibile se questi sono intesi come SPA completamente separati.

Per avere due file separati - identici - .htaccessi punti importanti sono:

  • Rendi relativa la stringa di sostituzione , ad es. nessun prefisso barra.
  • Non includere una RewriteBasedirettiva. (Che sovrascriverebbe il prefisso di directory.)

Quando la stringa di RewriteRule sostituzione è un percorso relativo , il prefisso della directory (cioè la posizione del .htaccessfile) viene aggiunto di nuovo alla fine del processo di riscrittura.

Quindi, entrambi /.htaccesse /admin/.htaccessconterrebbero direttive identiche:

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

TUTTAVIA, una leggera differenza con questa soluzione e la soluzione dell'OP è che la admin/parte del percorso URL non viene passata al pathparametro URL. Puoi codificare questo codice se necessario. per esempio. index.html?path=admin/$1. O tieni conto di questo nel tuo script.

La prima RewriteRuleè solo un'ottimizzazione minore che impedisce ulteriori controlli del filesystem dopo che la richiesta è già stata riscritta index.html.

Nota che ho cambiato (.*)(0 o più) in (.+)(1 o più). Ciò evita il controllo della directory aggiuntivo quando si richiede la directory principale. cioè. example.com/e example.com/admin/. Non stai riscrivendo queste richieste, ma invece fai affidamento su DirectoryIndex index.htmlun'impostazione appropriata: questa è l'impostazione predefinita nella configurazione del server.

Poiché la stringa di sostituzione ( index.php?page=$1) è relativa, quando nella radice del documento verrà effettivamente riscritta in /index.phpe quando in /admin/.htaccessessa riscriverà effettivamente in /admin/index.php.

Si noti che le direttive mod_rewrite /admin/.htaccesssovrascrivono completamente le direttive mod_rewrite nel .htaccessfile genitore poiché le direttive mod_rewrite non vengono ereditate di default (a differenza di altri moduli).


In alternativa, per evitare ripetizioni, pur mantenendo due .htaccessfile separati , è possibile abilitare l'ereditarietà mod_rewrite nel /admin/.htaccessfile. Per esempio...

Nel /.htaccessfile radice :

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

Quindi, in /admin/.htaccessavresti invece il seguente:

RewriteEngine On
RewriteOptions Inherit

Questo eredita le direttive genitore mod_rewrite come se fossero letteralmente copiate sul posto nel /admin/.htaccessfile.

Tuttavia, questo aggiunge un ulteriore livello di complessità. A parte il fatto che lo SPA /adminora dipende dal .htaccessfile root , ora devi stare attento a non aggiungere direttive di rottura al .htaccessfile root .


A parte:

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 prima condizione che verifica la presenza di "admin" nel percorso dell'URL (per inciso, questo verifica la presenza di "admin" ovunque nel percorso dell'URL - che non è strettamente corretto) non è richiesta - il controllo può essere eseguito in modo più ottimale nel RewriteRuledirettiva stessa. Per esempio:

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

Queste due regole possono essere combinate in una se lo si desidera, possibilmente a scapito di una certa chiarezza. Per esempio:

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

Il $1backreference quindi contiene il prefisso del percorso opzionale, o admin/o niente . E $0contiene la corrispondenza completa.

2 eric Jul 14 2020 at 06:35

Qui è dove ho commesso un errore:

Nota che ora ho 2 .htaccess. Uno su root e un altro nella sottodirectory / admin. Entrambi contengono gli stessi codici .htaccess. Il motivo è che ho un altro SPA in esecuzione nella directory principale.

Semplicemente aggiustando la mia radice .htaccess ed eliminando quello .htaccessche era nella sottodirectory / admin ha risolto il problema principale descritto nella mia domanda.

.Htaccess radice :

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

In realtà non conosco la risposta al tuo problema, ma posso suggerirti di giocare con la Locationdirettiva; qualcosa di simile a

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

Spero che sia di aiuto.