Adresele URL ale routerului React nu funcționează când se reîmprospătează sau se scrie manual

Folosesc React-router și funcționează bine în timp ce dau clic pe butoanele de link, dar când îmi reîmprospătesc pagina web, nu se încarcă ceea ce vreau.

De exemplu, sunt în localhost/joblist și totul este în regulă pentru că am ajuns aici apăsând un link. Dar dacă reîmprospătesc pagina web, primesc:

Cannot GET /joblist

Implicit, nu a funcționat așa. Inițial aveam adresa URL ca localhost/#/ și localhost/#/joblist și au funcționat perfect. Dar nu-mi place acest tip de URL, așa că încercând să șterg acel #, am scris:

Router.run(routes, Router.HistoryLocation, function (Handler) {
 React.render(<Handler/>, document.body);
});

Această problemă nu se întâmplă cu localhost/, acesta returnează întotdeauna ceea ce vreau.

EDITARE: această aplicație are o singură pagină, așa că /joblist nu trebuie să solicite nimic niciunui server.

EDIT2: întregul meu router.

var routes = (
    <Route name="app" path="/" handler={App}>
        <Route name="joblist" path="/joblist" handler={JobList}/>
        <DefaultRoute handler={Dashboard}/>
        <NotFoundRoute handler={NotFound}/>
    </Route>
);

Router.run(routes, Router.HistoryLocation, function (Handler) {
  React.render(<Handler/>, document.body);
});

person DavidDev    schedule 13.01.2015    source sursă
comment
cu excepția cazului în care utilizați htaccess pentru a încărca pagina principală de turneu și a spune routerului să folosească location.pathname nu va funcționa..   -  person CJT3    schedule 20.01.2015
comment
Cum ai șters acel simbol #? Mulțumesc!   -  person SudoPlz    schedule 06.06.2015
comment
Dacă vă găzduiți aplicația react într-o găleată S3, puteți pur și simplu să setați documentul de eroare la index.html. Acest lucru se va asigura că index.html este lovit indiferent de situație.   -  person Trevor Hutto    schedule 30.07.2016
comment
În cazul meu, funcționează bine în Windows, dar nu și în Linux   -  person Ejaz Karim    schedule 04.12.2017
comment
Aceasta este referința care a ajutat la rezolvarea problemei mele: github.com/facebook/create-react-app/blob/master/packages/   -  person jimbotron    schedule 10.07.2018


Răspunsuri (52)


Uitând la comentariile la răspunsul acceptat și la natura generică a acestei întrebări („nu funcționează”), m-am gândit că acesta ar putea fi un loc bun pentru câteva explicații generale despre problemele implicate aici. Deci, acest răspuns este conceput ca informații de fundal/elaborare asupra cazului de utilizare specific al OP. Vă rog să mă îndurați.

Partea server vs partea clientului

Primul lucru important de înțeles despre acest lucru este că acum există 2 locuri în care URL-ul este interpretat, în timp ce înainte era doar 1 în „pe vremuri”. În trecut, când viața era simplă, unii utilizatori trimiteau o solicitare pentru http://example.com/about către server, care inspecta partea de cale a adresei URL, determina că utilizatorul solicita pagina despre și apoi trimitea înapoi acea pagină.

Cu rutarea pe partea client, care este ceea ce oferă React-Router, lucrurile sunt mai puțin simple. La început, clientul nu are încă niciun cod JS încărcat. Deci, prima solicitare va fi întotdeauna către server. Aceasta va returna apoi o pagină care conține etichetele de script necesare pentru a încărca React și React Router etc. Faza 2 începe doar după ce s-au încărcat acele scripturi. În faza 2, când utilizatorul face clic pe linkul de navigare „Despre noi”, de exemplu, adresa URL este schimbată numai local în http://example.com/about (făcut posibil de History API), dar nu se face nicio solicitare către server. În schimb, React Router își face treaba pe partea clientului, determină ce vizualizare React să randeze și o redă. Presupunând că pagina dvs. despre nu trebuie să efectueze apeluri REST, este deja făcută. Ați trecut de la Acasă la Despre noi fără ca vreo solicitare de server să fi declanșat.

Deci, practic, atunci când faceți clic pe un link, se rulează Javascript care manipulează adresa URL din bara de adrese, fără a provoca o reîmprospătare a paginii, ceea ce, la rândul său, face ca React Router să efectueze o tranziție de pagină pe client. -lateral.

Dar acum luați în considerare ce se întâmplă dacă copiați și lipiți adresa URL în bara de adrese și o trimiteți prin e-mail unui prieten. Prietenul tău nu ți-a încărcat site-ul încă. Cu alte cuvinte, ea este încă în faza 1. Niciun router React nu rulează încă pe computerul ei. Prin urmare, browserul ei va face o solicitare de server către http://example.com/about.

Și de aici încep necazurile tale. Până acum, ai putea scăpa doar plasând un HTML static la webroot-ul serverului tău. Dar asta ar da erori 404 pentru toate celelalte URL-uri când sunt solicitate de la server. Aceleași adrese URL funcționează bine pe partea clientului, deoarece acolo React Router face rutarea pentru dvs., dar eșuează pe partea serverului dacă nu vă faceți serverul să înțeleagă lor.

Combinând rutarea serverului și clientului

Dacă doriți ca URL-ul http://example.com/about să funcționeze atât pe server, cât și pe partea client, trebuie să configurați rute pentru aceasta atât pe server, cât și pe partea client. Are sens, nu?

Și de aici încep alegerile tale. Soluțiile variază de la ocolirea completă a problemei, printr-o rută catch-all care returnează HTML-ul de bootstrap, până la abordarea izomorfă completă în care atât serverul, cât și clientul rulează același cod JS.

.

Ocolind cu totul problema: Istoricul Hash

Cu Istoricul hash în loc de Istoricul browserului, adresa URL a paginii Despre ar arăta cam așa: http://example.com/#/about Partea de după simbolul hash (#) nu este trimisă la server. Deci serverul vede doar http://example.com/ și trimite pagina de index așa cum era de așteptat. React-Router va prelua partea #/about și va afișa pagina corectă.

Dezavantaje:

  • URL-uri „urâte”.
  • Redarea pe partea serverului nu este posibilă cu această abordare. În ceea ce privește optimizarea pentru motoarele de căutare (SEO), site-ul dvs. web constă dintr-o singură pagină cu aproape deloc conținut.

.

Prindele pe toate

Cu această abordare, utilizați Istoricul browserului, dar doar configurați un catch-all pe server care trimite /* la index.html, oferindu-vă efectiv aceeași situație ca și în Istoricul Hash. Cu toate acestea, aveți adrese URL curate și puteți îmbunătăți această schemă mai târziu fără a fi nevoie să invalidați toate favoritele utilizatorului.

Dezavantaje:

  • Mai complex de configurat
  • Încă nu este un SEO bun

.

Hibrid

În abordarea hibridă, extindeți scenariul catch-all adăugând scripturi specifice pentru anumite rute. Ai putea crea niște scripturi PHP simple pentru a returna cele mai importante pagini ale site-ului tău cu conținut inclus, astfel încât Googlebot să poată vedea cel puțin ce este pe pagina ta.

Dezavantaje:

  • Și mai complex de configurat
  • Doar SEO bun pentru acele rute pe care le acordați un tratament special
  • Duplicarea codului pentru redarea conținutului pe server și client

.

izomorf

Ce se întâmplă dacă folosim Node JS ca server, astfel încât să putem rula același cod JS la ambele capete? Acum, avem toate rutele noastre definite într-o singură configurare a routerului de reacție și nu trebuie să ne duplicăm codul de randare. Acesta este „Sfântul Graal”, ca să spunem așa. Serverul trimite exact același marcaj cu care am ajunge dacă tranziția paginii ar fi avut loc pe client. Această soluție este optimă în ceea ce privește SEO.

Dezavantaje:

  • Serverul trebuie (să poată) rula JS. Am experimentat cu Java i.c.w. Nashorn, dar nu funcționează pentru mine. În practică, înseamnă mai ales că trebuie să utilizați un server bazat pe Node JS.
  • Multe probleme de mediu dificile (folosirea window pe partea serverului etc.)
  • Curbă abruptă de învățare

.

Pe care ar trebui să-l folosesc?

Alege-l pe cel cu care poți scăpa. Personal, cred că catch-all este destul de simplu de configurat, așa că acesta ar fi minimul meu. Această configurație vă permite să îmbunătățiți lucrurile în timp. Dacă utilizați deja Node JS ca platformă de server, cu siguranță aș investiga realizarea unei aplicații izomorfe. Da, este greu la început, dar odată ce înțelegi, este de fapt o soluție foarte elegantă la problemă.

Deci, practic, pentru mine, acesta ar fi factorul decisiv. Dacă serverul meu rulează pe Node JS, aș deveni izomorf; în caz contrar, aș opta pentru soluția Catch-all și aș extinde-o (soluție hibridă) pe măsură ce timpul trece și cerințele SEO o cer.

Dacă doriți să aflați mai multe despre redarea izomorfă (numită și „universală”) cu React, există câteva tutoriale bune pe acest subiect:

De asemenea, pentru a începe, vă recomand să vă uitați la câteva truse de pornire. Alegeți unul care se potrivește cu alegerile dvs. pentru stiva de tehnologie (rețineți, React este doar V-ul în MVC, aveți nevoie de mai multe lucruri pentru a crea o aplicație completă). Începeți cu privire la cel publicat de Facebook însuși:

Sau alegeți unul dintre multele comunitate. Există acum un site frumos care încearcă să le indexeze pe toate:

Am inceput cu astea:

În prezent, folosesc o versiune home-brew a redării universale care a fost inspirată din cele două kituri de pornire de mai sus, dar acestea sunt depășite acum.

Mult succes cu căutarea ta!

person Stijn de Witt    schedule 14.04.2016
comment
Super post Stijn! Ați recomanda să folosiți un kit de pornire pentru o aplicație Isomorphic react? Dacă da, ați putea da un exemplu de unul pe care l-ați prefera? - person Chris; 29.04.2016
comment
@Chris Îmi pare rău pentru răspunsul întârziat, am fost într-o călătorie. De fapt, am încercat câteva kituri de pornire izomorfe. Voi adăuga câteva informații despre el în postare. - person Stijn de Witt; 06.05.2016
comment
@Stijn - Asta mi-a clarificat cu adevărat câteva lucruri, mulțumesc. Puteți clarifica tehnica „catch-all”? Acesta pare a fi pasul logic pentru mine în acest moment, dar nu sunt sigur unde să găsesc mai multe detalii despre cum să realizez acest lucru... - person Paulos3000; 30.10.2016
comment
@Paulos3000 Depinde de ce server folosești. Practic definiți o rută pentru /* și îl faceți să răspundă cu pagina dvs. HTML. Lucrul dificil aici este să vă asigurați că nu interceptați solicitările pentru fișierele .js și .css cu această rută. - person Stijn de Witt; 30.10.2016
comment
@Paulos3000 Vezi aici câteva întrebări legate de: pentru Apache/php, pentru Express/js, pentru J2E/Java. - person Stijn de Witt; 30.10.2016
comment
Aș folosi un server Express. Am văzut codul pentru el, dar nu sunt complet sigur cum să-l integrez... Cum aș face-o cu webpack, de exemplu? - person Paulos3000; 30.10.2016
comment
@Paulos3000 Express face acest lucru foarte simplu. Doar asigurați-vă că adăugați ceva în acest sens ca ultimul handler: app.use('*', function(req, res, next) {res.send('<DOCTYPE html ....')}); - person Stijn de Witt; 01.11.2016
comment
...dar desigur, pe măsură ce utilizați expres, ar trebui să investigați soluția izomorfă/universală ;) - person Stijn de Witt; 01.11.2016
comment
Interesant, de când am creat pentru prima dată acest răspuns, Facebook însuși a introdus un kit de pornire. Poate incearca asta? github.com/facebookincubator/create-react-app - person Stijn de Witt; 01.11.2016
comment
Vă mulțumesc foarte mult - acest lucru mi-a clarificat aspecte ale direcționării pe care nu le făcuseră căutarea pe Google și citirea documentelor oficiale React. Pot să vă sugerez să îl trimiteți celor de la React pentru a le include în documentele lor? - person John McGrath; 17.12.2016
comment
@JohnMcGrath Mulțumesc și mă bucur că te-a ajutat. Documentele React Router ar fi probabil mai potrivite. Sunt open source, așa că ați putea să le oferiți ca o contribuție... Poate îi îndrumați mai întâi la această postare și îi întrebați dacă sunt interesați? - person Stijn de Witt; 20.12.2016
comment
@Stijn de Witt Aceasta este o clarificare grozavă și răspuns bine pe acest subiect. Cu toate acestea, care sunt opțiunile când aplicația dvs. ar putea fi difuzată într-un subdirector (de iis, de exemplu). Adică: domain/appName/routeName sau domain/appName/subfolder/routeName - person Sagiv b.g; 19.03.2017
comment
Salut, incerc solutia de hash, insa nu am avut succes. Se primește createMemoryHistory is not a function eroare. Te deranjează să te uiți? stackoverflow.com/questions/45002573/ - person Leon Gaban; 10.07.2017
comment
@LeonGaban Se pare că, de când a fost scris acest răspuns, React Router și-a schimbat implementarea. Acum au instanțe de router diferite pentru diferitele istorii și fac configurarea istoricului în fundal. Principiile de bază sunt încă aceleași. - person Stijn de Witt; 17.07.2017
comment
@YarinDekel Mulțumesc! Și da, poate ai dreptate în ceea ce privește create-react-app, deoarece CRA nu acceptă SSR din cutie :( - person Stijn de Witt; 08.01.2019
comment
@Stijndewitt M-am împiedicat de o soluție, cum ar fi „catch-all” pe care l-ați menționat, care ar putea elimina dezavantajul SEO. Cu toate acestea, implică doar pisica. S-ar putea să merite să vă actualizați răspunsul pentru a-l include? - person ns533; 07.07.2019
comment
@ns533 Puteți explica cum ar elimina dezavantajul SEO? AFAICT, este ca regulile de rescrie în Apache... Înseamnă că tot ajunge doar să trimită o pagină aproape goală în care crawlerele nu vor putea găsi niciun conținut. - person Stijn de Witt; 08.07.2019
comment
@StijndeWitt Dacă crawler-ul web nu redă pagina cu JavaScript activat, atunci cred că nu ar face acest lucru. Totuși, am citit că crawlerele web de la Google văd întreaga pagină. Combinând aceste informații cu o regulă if care redirecționează www.mysite.com/blogpost/* către index.html-ul meu (google nu e mai înțelept), atunci crawler-ul web al Google nu ar trebui să vadă fiecare postare de blog ca o pagină unică? - person ns533; 21.07.2019
comment
@ns533 Da, cred că Google va putea să-l indexeze, deoarece se pare că rulează într-adevăr javascript. Cu toate acestea, nu sunt sigur ce, de ex. Bing și Yahoo fac... - person Stijn de Witt; 31.07.2019
comment
@StijndeWitt Postare foarte utilă, există vreo resursă care să explice această abordare Catch All implementată în .net? Tocmai m-am gândit că șablonul .Net Core React Web App creat de Visual Studio are această problemă exactă. Încercarea de a accesa backend-ul cu URL-ul funcționează pentru prima dată. A doua oară nu mai merge niciodată la backend. Nu găsesc o modalitate de a o rezolva. - person Arthur Medeiros; 08.11.2019
comment
@StijndeWitt O explicație cuprinzătoare foarte bună. Cred că soluția generală nu este mare lucru și ușor de configurat pentru back-end precum Django - person Mohammed Shareef C; 14.12.2019
comment
@ns533 Nu cred că acea soluție se limitează la Tomcat. Nginx poate face față cu ușurință la asta. Oricum, este aceeași soluție catch-all, dar gestionată de serverul web (sau serverul proxy invers). - person Mohammed Shareef C; 14.12.2019
comment
Grozav răspuns! Am postat recent un articol, care conține câteva vizualizări ale ceea ce se întâmplă în timpul rutării. Sper că va ajuta valerii-udodov.com/2020 /01/24/ Salutări - person Val; 29.01.2020
comment
Un lucru care nu a fost subliniat a fost că, dacă încărcați aplicația și apoi schimbați manual adresa URL în browser la o adresă URL pe care routerul o acceptă, întreaga aplicație va fi reîmprospătată. Am avut impresia că browserul va direcționa acest lucru în aplicație, dar nu este cazul. Browserul nu știe nimic despre React și face ceea ce face întotdeauna, și anume să încarce conținutul pentru adresa URL din backend. - person AndroidDev; 10.04.2020
comment
Da, modalitatea de a manipula adresa URL fără ca aceasta să preia o pagină nouă de pe server este să folosești API-ul Istoric. Puteți deschide o consolă de dezvoltare și rula o linie de JS acolo dacă doriți să testați navigarea pe partea clientului. - person Stijn de Witt; 12.04.2020
comment
@StijndeWitt Tocmai a votat acest răspuns bine scris. :) Un singur lucru însă: în abordarea Catch-all, ce înseamnă fără a fi nevoie să invalidezi toate favoritele utilizatorului tău.? ???? - person Glenn Mohammad; 12.04.2020
comment
@GlennMohammad Imaginați-vă că începeți cu abordarea Hash History și utilizatorii fac un favorit (marcaj) la https://example.com/#/about, dacă mai târziu treceți la server, redarea marcajelor lor nu va mai funcționa. Dacă începeți cu Catch All și faceți https://example.com/about return index.html, puteți implementa ulterior randarea pe partea serverului, iar marcajele utilizatorului vor funcționa în continuare. - person Stijn de Witt; 13.04.2020
comment
Am găsit o problemă amuzantă cu HashRouter: prima dată când introduc adresa URL, funcționează bine, dar dacă scriu același lucru din nou, face o reîncărcare completă a aplicației. De exemplu fiind în locahost:3000/ eu tast locahost:3000/test care nu există, atunci HashRouter nu reîncarcă pagina. Dar dacă încerci să trimiți din nou aceeași solicitare locahost:3000/test aplicația se reîncarcă... Mă întreb de ce... ???? - person Watchmaker; 20.04.2020
comment
răspunsul la această întrebare este foarte bine explicat, dar soluția mea a fost adăugarea import * ca serviceWorker din ./serviceWorker; și serviceWorker.register() în App.js și pot reîmprospăta paginile fără referințe urâte la adrese URL: medium.com/@krishnarai1985/ - person EduardoUstarez; 17.09.2020
comment
@EduardoUstarez Soluția ta nu funcționează în cazul general. Doar trimite un e-mail un link către un prieten pentru a-l testa. Lucrătorii de servicii sunt un lucru pe partea clientului. Acestea funcționează numai pentru clienții care au încărcat deja pagina în trecut și au instalat serviciul de lucru. De fapt, aveți nevoie de o soluție pe partea serverului dacă doriți ca adresele URL să funcționeze în toate cazurile. - person Stijn de Witt; 28.12.2020
comment
doar redirecționarea răspunsurilor 404 și 403 către /index.html nu ar rezolva problema? - person tymik; 30.12.2020
comment
@tymik Aș considera că este un hack murdar. Vreau ca site-ul meu să returneze 404 pentru adresele URL care nu există. Cu o astfel de soluție, toate URL-urile vor redirecționa către index.html, dar nu asta vreau să facă site-ul meu. Poate fi totuși acceptabil pentru tine. - person Stijn de Witt; 03.01.2021
comment
Cum începeți cu abordarea Catch-all? - person Yash Karanke; 04.01.2021
comment
@StijndeWitt, dar veți gestiona apoi 404 în routerul dvs. și veți returna orice doriți în aplicația dvs. - aceasta pare a fi o soluție destul de bună pentru aplicațiile cu o singură pagină. Funcționează destul de bine cu CloudFront în acest fel. - person tymik; 04.01.2021
comment
@YashKaranke Care este serverul tău? Trebuie să-l configurați pentru a returna index.html pentru toate adresele URL pe care le va folosi aplicația dvs. Dar asigurați-vă că face acest lucru numai pentru HTML, nu pentru imagini, scripturi etc. - person Stijn de Witt; 06.01.2021
comment
@StijndeWitt Apache, am adăugat un fișier .htaccess în folderul public și funcționează perfect acum - person Yash Karanke; 06.01.2021
comment
Am soluția pentru asta, m-am confruntat recent cu această problemă într-un proiect, probabil că voi scrie un răspuns mai târziu când voi avea timp - person Inzamam Malik; 10.07.2021
comment
nu este nevoie să utilizați HashRouter - person Inzamam Malik; 10.07.2021

Răspunsurile de aici sunt toate extrem de utile, ceea ce a funcționat pentru mine a fost configurarea serverului meu Webpack pentru a aștepta rutele.

devServer: {
   historyApiFallback: true,
   contentBase: './',
   hot: true
},

HistoryApiFallback este ceea ce a rezolvat această problemă pentru mine. Acum rutarea funcționează corect și pot reîmprospăta pagina sau pot introduce direct adresa URL. Nu trebuie să vă faceți griji cu privire la operațiunile de lucru pe serverul dumneavoastră nod. Acest răspuns, evident, funcționează numai dacă utilizați webpack.

EDIT: vedeți răspunsul meu aici pentru un motiv mai detaliat pentru care este necesar: https://stackoverflow.com/a/37622953/5217568

person jmancherje    schedule 26.05.2016
comment
Rețineți că echipa Webpack recomandă împotriva utilizarea serverului de dezvoltare în producție. - person Stijn de Witt; 13.06.2016
comment
Pentru scopuri de dezvoltare generică, aceasta este cea mai bună soluție. historyApiFallback este suficient. Ca și pentru toate celelalte opțiuni, poate fi setat și din CLI cu steag-ul --history-api-fallback. - person Marco Lazzeri; 27.10.2016
comment
@Kunok Nu. Aceasta este o soluție rapidă pentru dezvoltare, dar va trebui totuși să găsiți ceva pentru producție. - person Stijn de Witt; 31.05.2017
comment
contentBase :':/' deoarece fișierele aplicației dvs. pot fi accesate de la adresa URL - person Nezih; 21.02.2018
comment
Am avut aceasta problema pe server si de asemenea local. Acest lucru s-a rezolvat pentru local. .htaccess fixat pe server. - person Izabela Furdzik; 05.06.2021
comment
Funcționează pentru React 17. Mulțumesc - person prathameshk73; 26.06.2021

Puteți schimba fișierul .htaccess și puteți introduce acesta:

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

Folosesc react: "^16.12.0" și react-router: "^5.1.2" Această metodă este Catch-all și este probabil cea mai simplă modalitate de a începe.

person BrahimS    schedule 14.11.2016
comment
Acest lucru funcționează bine! și cel mai ușor dacă nu doriți să vă restructurați aplicația - person mhyassin; 13.02.2018
comment
Nu uitați RewriteEngine On ca prima linie - person Kai Qing; 01.11.2018
comment
Rețineți că acest răspuns se referă la config pe un server Apache. Aceasta nu face parte dintr-o aplicație React. - person Colton Hicks; 17.07.2019
comment
Nu am inteles raspunsurile de mai sus. Niciunul dintre tutoriale nu a spus că linkurile mele nu vor funcționa live. Cu toate acestea, acest fișier htaccess simplu a funcționat. Mulțumiri - person Thomas Williams; 26.03.2020
comment
Acest lucru funcționează și pentru exportul static next.js. Deoarece tomcat-ul nu este similar cu nodul, avem nevoie de această configurație suplimentară pentru exportul static next.js. - person giri-jeedigunta; 04.04.2020
comment
Funcționează frumos, ceea ce probabil nu este o coincidență. 80% dintre adresele URL profunde pot fi acum reîmprospătate, o îmbunătățire clară. - person Chris G; 29.05.2020
comment
Ma poate ajuta cineva? Unde este pus acest htaccess? Trebuie să rulați npm build după adăugarea fișierului? - person Muteshi; 05.09.2020
comment
Am npm run build și apoi am adăugat asta în .htacess în folderul de compilare și l-am încărcat pe cPanel, încă nu funcționează - person Tayyab Ferozi; 10.12.2020
comment
@TayyabFerozi Trebuie să vă asigurați că calea după RewriteBase și după ultimele RewriteRule se potrivește cu folderul în care se află aplicația (dacă este un subdosar) - person Jason Ellis; 22.12.2020
comment
Am avut aceasta problema pe server si de asemenea local. S-a rezolvat pentru server. devServer config a rezolvat-o local. - person Izabela Furdzik; 05.06.2021

Pentru utilizatorii React Router V4:

Dacă încercați să rezolvați această problemă prin tehnica Hash History menționată în alte răspunsuri, rețineți că

<Router history={hashHistory} >

nu funcționează în V4, vă rugăm să utilizați HashRouter în schimb:

import { HashRouter } from 'react-router-dom'

<HashRouter>
  <App/>
</HashRouter>

Referință: HashRouter

person user2875289    schedule 18.04.2017
comment
Ați putea oferi detalii despre motivul pentru care HashRouter rezolvă această problemă? Linkul pe care l-ai furnizat nu îmi explică. De asemenea, există vreo modalitate de a ascunde hash-ul din cale? Folosisem BrowserRouter, dar am întâlnit această problemă 404 cu el.. - person Ian Smith; 07.06.2020
comment
Folosisem un router de browser și a provocat o eroare 404 la reîmprospătare, dar apoi am înlocuit routerul de browser cu un router hash și nu funcționează bine. Mulțumiri - person newbie; 31.07.2020

Am folosit create-react-app pentru a face un site web chiar acum și am avut aceeași problemă prezentată aici. Folosesc BrowserRouting din pachetul react-router-dom. Rulez pe un server Nginx și ceea ce mi-a rezolvat a fost să adaug următoarele la /etc/nginx/yourconfig.conf

location / {
  if (!-e $request_filename){
    rewrite ^(.*)$ /index.html break;
  }
}

Ceea ce corespunde cu adăugarea următoarelor la .htaccess în cazul în care rulați Appache

Options -MultiViews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.html [QSA,L]

Aceasta pare să fie și soluția sugerată de Facebook însuși și poate fi găsită aici

person Aidin    schedule 04.09.2017
comment
Wow, o soluție atât de simplă pentru nginx; funcționează ca un farmec, ca un nou utilizator nginx. Doar copy-paste și gata. +1 pentru conectarea la documentația oficială fb. Mult de mers. - person user3773048; 13.01.2019
comment
Pentru înregistrare: folosesc o instanță AWS cu nginx și o aplicație Angular. Acest lucru funcționează. - person Diego Sarmiento; 03.06.2019
comment
tu mă salvezi. Încercam să-mi rezolv problema de ieri, am obosit câteva soluții, dar nu am reușit. în cele din urmă m-ai ajutat să rezolv această problemă cu routerul. ah multumesc mult frate - person Sharifur Robin; 22.09.2019
comment
Este nevoie de ceva diferit pentru react: ^16.8.6, react-router: ^5.0.1? Am încercat aceste soluții (atât nginx, cât și apache) și nu funcționează. - person Mark A. Tagliaferro; 21.10.2019
comment
Deoarece Facebook nu și-a schimbat documentația în acest sens, pot doar să presupun că procedura este aceeași. Nu l-am mai incercat de ceva vreme insa. - person Aidin; 21.10.2019
comment
Te confrunți cu asta timp de săptămâni și aceasta este singura soluție care funcționează. Mulțumiri - person abby; 29.05.2020
comment
Bună, vă rog să-mi spuneți cum va funcționa dacă folderul react este alias, nu root? - person krishna lodha; 25.05.2021

În index.html head, adăugați următoarele:

<base href="/ro/">
<!-- This must come before the css and javascripts -->

Apoi, atunci când rulați cu serverul de dezvoltare webpack, utilizați această comandă.

webpack-dev-server --mode development --hot --inline --content-base=dist --history-api-fallback

--history-api-fallback este partea importantă

person Efe Ariaroo    schedule 01.04.2018
comment
Acest lucru a funcționat grozav! Vreo link-uri pentru a citi mai multe despre cum ați obținut/găsit acea soluție? - person justDan; 26.06.2018
comment
Scuze frate. L-am găsit prin tehnica încercată și adevărată a încercării și erorii. - person Efe Ariaroo; 30.06.2018
comment
Merită menționat faptul că, dacă utilizați un href de bază care nu este /, atunci HashRouter nu va funcționa (dacă utilizați rutarea hash) - person scrowler; 17.01.2019
comment
Eticheta ‹base href=/› a făcut-o pentru mine. Multumesc pentru asta. Serverul de dezvoltare Webpack a tot încercat să ia pachetul de pe cale/‹pachet› și nu a reușit. - person Malisbad; 26.03.2019
comment
Folosesc modul React.js + Webpack. Am adăugat parametrul --history-api-fallback în fișierul package.json. Apoi, reîmprospătarea paginii funcționează corect. Fiecare când schimb codul, pagina web se reîmprospătează automat. ``` scripturi: { start: rimraf build && cross-env NODE_ENV='dezvoltare' webpack --mode development && cross-env NODE_ENV=dezvoltare webpack-dev-server --history-api-fallback, ... } `` ` - person NinjaDev; 13.08.2020

Routerul poate fi apelat în două moduri diferite, în funcție de faptul că navigarea are loc pe client sau pe server. Îl aveți configurat pentru funcționarea pe partea clientului. Parametrul cheie este al doilea pentru metoda de rulare, locația .

Când utilizați componenta React Router Link, aceasta blochează navigarea în browser și apelează la tranzițieTo pentru a efectua o navigare pe partea clientului. Utilizați HistoryLocation, așa că folosește API-ul istoric HTML5 pentru a completa iluzia de navigare prin simularea noului URL în bara de adrese. Dacă utilizați browsere mai vechi, acest lucru nu va funcționa. Ar trebui să utilizați componenta HashLocation.

Când apăsați pe reîmprospătare, ocoliți tot codul React și React Router. Serverul primește cererea pentru /joblist și trebuie să returneze ceva. Pe server trebuie să treceți calea care a fost solicitată la metoda run pentru ca aceasta să reda vizualizarea corectă. Puteți folosi aceeași hartă a rutei, dar probabil veți avea nevoie de un apel diferit la Router.run. După cum subliniază Charles, puteți utiliza rescrierea URL pentru a gestiona acest lucru. O altă opțiune este să utilizați un server node.js pentru a gestiona toate solicitările și a transmite valoarea căii ca argument locație.

În expres, de exemplu, ar putea arăta astfel:

var app = express();

app.get('*', function (req, res) { // This wildcard method handles all requests

    Router.run(routes, req.path, function (Handler, state) {
        var element = React.createElement(Handler);
        var html = React.renderToString(element);
        res.render('main', { content: html });
    });
});

Rețineți că calea cererii este transmisă către run. Pentru a face acest lucru, va trebui să aveți un motor de vizualizare pe partea serverului căruia îi puteți transmite HTML-ul redat. Există o serie de alte considerații folosind renderToString și în rularea React pe server. Odată ce pagina este redată pe server, atunci când aplicația dvs. se încarcă în client, aceasta va fi randată din nou, actualizând codul HTML redat pe server după cum este necesar.

person Todd    schedule 21.01.2015
comment
Scuzați-mă, puteți explica, vă rugăm, următoarea afirmație când apăsați pe reîmprospătare, ocoliți toate codurile React și React Router? De ce se întâmplă? - person VB_; 08.09.2015
comment
Routerul React este utilizat în mod normal pentru a gestiona diferite „căi” numai în browser. Există două moduri tipice de a face acest lucru: calea hash de stil mai vechi și API-ul istoric mai nou. O reîmprospătare a browserului va face o solicitare de server, care va ocoli codul routerului de reacție de la partea clientului. Va trebui să gestionați calea de pe server (dar numai dacă utilizați API-ul istoric). Puteți folosi routerul react pentru aceasta, dar va trebui să faceți ceva similar cu ceea ce am descris mai sus. - person Todd; 09.09.2015
comment
am înţeles. Dar cum să fie dacă serverul este pe un limbaj non-JS (să spunem Java)? - person VB_; 09.09.2015
comment
Lucrurile devin mai dificile în acest caz. Promisiunea aplicațiilor izomorfe este cel mai bine realizată prin utilizarea JS pe client și pe server. Dacă nu puteți rula JS în cadrul Java, nu veți avea cu adevărat izomorfism și nici nu veți putea folosi routerul de reacții. Există câteva soluții pe partea de server, cum ar fi ReactJS.NET, care pot face acest gen de lucruri. Cu toate acestea, este mai ușor să utilizați Node.js. - person Todd; 11.09.2015
comment
care este primul parametru rute din acest răspuns? Pentru că atunci când includeți ceva de genul ‹Nume rută=cale rădăcină=/ handler={App} /› obțineți o eroare SyntaxError: Unexpected token ‹ - person Code Uniquely; 15.10.2015
comment
scuze... vrei să spui că ai nevoie de un server expres pentru a reda o rută care nu este root? Am fost mai întâi uimit de faptul că definiția izomorfismului nu includea preluarea datelor în conceptul său (lucrurile sunt extrem de complexe dacă doriți să faceți vizualizarea CU serverul de date, deși ar fi o nevoie evidentă de SEO - și izomorfismul o pretinde). Acum sunt ca și cum WTF reacționează, serios... Corectează-mă dacă greșesc, ember/unghiular/backbone necesită un server pentru a reda o rută? Chiar nu înțeleg această cerință umflată de a folosi rute - person Ben; 17.10.2015
comment
@Ben Corectează-mă dacă greșesc, ember/angular/backbone necesită un server pentru a reda o rută? Da, de fapt o fac atunci când utilizați locația istorică („URL-uri reale”). Toate cadrele Javascript fac. Amintiți-vă, când solicitați o adresă URL, accesați mai întâi serverul. Ceea ce se întâmplă este că OP nu rulează corect de partea serverului. El ar trebui fie să folosească locația hash, fie să configureze serverul să servească întotdeauna HTML pe toate rutele posibile. - person Stijn de Witt; 17.11.2015
comment
Înseamnă că reîmprospătarea în react-router nu funcționează dacă aplicația mea react nu este izomorfă? - person Matt; 07.12.2015
comment
Pentru a face reîmprospătarea să funcționeze, trebuie să apelați routerul din codul client (mediu React implicit) și din codul serverului (Node.js). Dacă puteți face acest lucru, atunci aplicația dvs. este izomorfă. Rețineți că codul din acest răspuns nu reflectă modificările din noua versiune React Router 1.0 (de acum). - person Todd; 08.12.2015
comment
@Matt Dacă aplicația ta react nu este izomorfă (sau poate că nici măcar nu rulezi JS pe partea de server, dar, să zicem, PHP), cel mai bun pariu este să ai doar un script pe server care returnează aceeași pagină pentru toate posibile rute. Numai câteva HTML bootstrap generice vor fi trimise clientului. Odată ajuns pe client, React-Router se uită la adresa URL și lucrurile vor funcționa conform așteptărilor. Dar dezavantajul este legat de SEO. Google va vedea doar acel HTML de bootstrap și nu va indexa site-ul dvs. - person Stijn de Witt; 14.04.2016

Dacă utilizați aplicația Create React:

Există totuși o plimbare grozavă a acestei probleme cu soluții pentru multe platforme de găzduire majore pe care le puteți găsi AICI pe pagina Creați aplicația React. De exemplu, folosesc React Router v4 și Netlify pentru codul meu de front-end. Tot ce a fost nevoie a fost să adaug un fișier în folderul meu public ("_redirects") și o linie de cod în acel fișier:

/*  /index.html  200

Acum site-ul meu redă corect căi precum mysite.com/pricing atunci când este introdus în browser sau când cineva apasă pe actualizare.

person Colton Hicks    schedule 09.06.2017
comment
dacă utilizați Apache HTTP Server, atunci .htaccess nu funcționează, verificați versiunea apache deoarece în versiunea 2.3.9 și ulterioară AllowOverride< /b> este Niciuna, încercați să schimbați AllowOverride în Toate. verificați acest răspuns - person Muhammad Adam C; 13.04.2021

Dacă găzduiți o aplicație react prin AWS Static S3 Hosting și CloudFront

Această problemă a apărut de către CloudFront care a răspuns cu un mesaj 403 Acces refuzat, deoarece se aștepta ca /some/other/path să existe în folderul meu S3, dar acea cale există doar intern în rutarea React cu react-router.

Soluția a fost configurarea unei reguli de distribuire a paginilor de eroare. Accesați setările CloudFront și alegeți distribuția. Apoi accesați fila „Pagini de eroare”. Faceți clic pe „Creați un răspuns de eroare personalizat” și adăugați o intrare pentru 403, deoarece acesta este codul de stare de eroare pe care îl primim. Setați Calea paginii de răspuns la /index.html și codul de stare la 200. Rezultatul final mă uimește prin simplitatea sa. Pagina de index este difuzată, dar URL-ul este păstrat în browser, așa că odată ce aplicația react se încarcă, detectează calea URL și navighează la ruta dorită.

Regula 403 pentru paginile de eroare

person th3morg    schedule 23.11.2017
comment
Este exact ceea ce aveam nevoie. Mulțumesc. - person Jonathan; 19.09.2019
comment
Deci... toate URL-urile tale funcționează, dar returnează codul de stare 403? Nu este corect. Codurile de stare așteptate ar trebui să fie în intervalul 2xx. - person Stijn de Witt; 21.10.2019
comment
@StijndeWitt Nu sunt sigur că înțelegi corect. CloudFront se va ocupa de totul - clientul nu va vedea niciun cod de stare 403. Redirecționarea are loc pe partea de server, redă pagina de index, menține adresa URL și, ca rezultat, furnizează ruta corectă. - person th3morg; 22.10.2019
comment
@th3morg Ah, da, văd acum. Am ratat faptul că vă permite, de asemenea, să completați codul de stare a răspunsului ca 200. Deci, practic, mapați starea 403 la starea 200... Arata bine... cu excepția faptului că, poate, dacă obțineți 403 ca ​​rezultat din alt motiv nu o vei putea vedea din cauza asta. - person Stijn de Witt; 23.10.2019
comment
@StijndeWitt Este în special un 403 de la CloudFront, așa că dacă ați spune că faceți un apel API care a dus la un răspuns 403 asincron de la site-ul dvs., acesta s-ar comporta normal. Nu îmi pot imagina un scenariu în care ați dori să expuneți un comportament 403 de la CloudFront însuși, deși poate că există unul. Această soluție ar trebui totuși să funcționeze pentru 99+% din cazuri de utilizare. - person th3morg; 23.10.2019
comment
mulțumesc pentru asta @th3morg. Funcționează această configurație și pentru căi cu mai multe niveluri? Funcționează grozav pentru mine dacă există vreo cale la nivel rădăcină, cum ar fi domeniu/înscriere, domeniu/login, domeniu/‹documentId›, dar nu funcționează pentru căi cu mai multe niveluri, cum ar fi domeniu/document/‹documentId›. - person Pargles; 03.02.2020
comment
O ființă frumoasă! A trebuit să-l setez pentru un răspuns 404 și a funcționat ca un farmec! - person Nnanyielugo; 06.07.2020

Acest lucru vă poate rezolva problema

M-am confruntat cu aceeași problemă și în aplicația ReactJS în modul Production. Iată a doua soluție la problemă.

1.Schimbați istoricul de rutare în hashHistory în loc de browserHistory în locul lui

<Router history={hashHistory} >
   <Route path="/home" component={Home} />
   <Route path="/aboutus" component={AboutUs} />
</Router>

Acum construiți aplicația folosind comanda

sudo npm run build

Apoi plasați folderul de compilare în folderul dvs. var/www/. Acum, aplicația funcționează bine cu adăugarea etichetei # în fiecare URL. ca

localhost/#/home localhost/#/aboutus

Soluția 2: fără eticheta # folosind browserHistory,

Setați-vă istoricul = {browserHistory} în routerul dvs., acum construiți-l folosind sudo npm run build.

Trebuie să creați fișierul conf pentru a rezolva pagina 404 negăsit, fișierul conf ar trebui să fie așa.

deschideți terminalul, introduceți comenzile de mai jos

cd /etc/apache2/sites-available ls nano sample.conf Adăugați conținutul de mai jos în el.

<VirtualHost *:80>
    ServerAdmin [email protected]
    ServerName 0.0.0.0
    ServerAlias 0.0.0.0
    DocumentRoot /var/www/html/

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
    <Directory "/var/www/html/">
            Options Indexes FollowSymLinks
            AllowOverride all
            Require all granted
    </Directory>
</VirtualHost>

Acum trebuie să activați fișierul sample.conf utilizând următoarea comandă

cd /etc/apache2/sites-available
sudo a2ensite sample.conf

apoi vă va cere să reîncărcați serverul apache, folosind sudo service apache2 reload sau restart

apoi deschideți folderul localhost/build și adăugați fișierul .htaccess cu conținutul de mai jos.

   RewriteEngine On
   RewriteBase /
   RewriteCond %{REQUEST_FILENAME} !-f
   RewriteCond %{REQUEST_FILENAME} !-d
   RewriteCond %{REQUEST_FILENAME} !-l
   RewriteRule ^.*$ / [L,QSA]

Acum aplicația funcționează normal.

Notă: schimbați 0.0.0.0 IP la adresa IP locală.

Dacă aveți îndoieli cu privire la acest lucru, nu ezitați să faceți un comentariu.

Sper să fie de ajutor altora.

person Venkatesh Somu    schedule 07.02.2017
comment
Va funcționa prima soluție pentru "react-router-dom": "^5.1.2"?, folosesc <BrowserRouter> - person 151291; 13.12.2019
comment
.htaccess a rezolvat-o pentru mine. - person beltrone; 03.02.2021
comment
unde, voi obține browserHistory, în soluția 2. - person Sushil; 06.02.2021
comment
adăugând doar fișierul .htaccess în folderul de compilare a remediat pentru mine, mulțumesc omule - person coderLogs; 19.05.2021

Dacă vă găzduiți aplicația react pe IIS, trebuie doar să adăugați un fișier web.config care conține:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.webServer>
    <httpErrors errorMode="Custom" existingResponse="Replace">
        <remove statusCode="404" subStatusCode="-1" />
        <error statusCode="404" path="/" responseMode="ExecuteURL" />
    </httpErrors>
  </system.webServer>
</configuration>

Acest lucru va spune serverului IIS să returneze pagina principală către client în loc de eroarea 404 și nu este nevoie să folosească istoricul hash.

person Chtiwi Malek    schedule 18.10.2017

Webpack Dev Server are o opțiune pentru a activa acest lucru. Deschideți package.json și adăugați --history-api-fallback. Aceste soluții au funcționat pentru mine.

react-router- tutorial

person sree    schedule 09.09.2016
comment
Este în regulă cu webpack-dev-server, dar cum repar asta pentru versiunea de producție? - person Hussain; 15.08.2018

Stiva de producție: React, React Router v4, BrowswerRouter, Express, Nginx

1) Utilizator BrowserRouter pentru URL-uri frumoase

// app.js

import { BrowserRouter as Router } from 'react-router-dom'

const App = () {
  render() {
    return (
        <Router>
           // your routes here
        </Router>
    )
  }
}

2) Adăugați index.html la toate solicitările necunoscute folosind /*

// server.js

app.get('/*', function(req, res) {   
  res.sendFile(path.join(__dirname, 'path/to/your/index.html'), function(err) {
    if (err) {
      res.status(500).send(err)
    }
  })
})

3) pachet webpack cu webpack -p

4) rulați nodemon server.js sau node server.js

EDIT: Poate doriți să lăsați nginx să se ocupe de acest lucru în blocul serverului și să ignorați pasul 2:

location / {
    try_files $uri /index.html;
}
person Isaac Pak    schedule 09.08.2017
comment
obținerea căii nedefinite - person Goutham; 10.08.2017
comment
@Goutham În partea de sus a fișierului server.js adăugați fie import path from 'path, fie const path = require('path') - person Isaac Pak; 10.08.2017
comment
pasul 2 (prind toate cu /*) tocmai mi-a salvat ziua. Mulțumesc! :) - person Atlas7; 22.11.2017
comment
Acest lucru funcționează, pentru cei care folosesc redux și sunt preocupați de un router conectat, vedeți acest exemplu: github.com/supasate/connected-react-router/tree/master/examples/ - person cjjenkinson; 16.04.2018

Adăugați asta la webpack.config.js:

devServer: {
    historyApiFallback: true
}
person suraj    schedule 11.09.2017
comment
Este grozav pentru dezvoltatori, dar nu ajută la versiunile de producție. - person KFunk; 05.05.2020

Încercați să adăugați fișierul „.htaccess” în folderul public cu codul de mai jos.

RewriteEngine On
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^ - [L]

RewriteRule ^ /index.html [L]  
person Kiran Joshi    schedule 29.06.2018
comment
Mulțumesc, asta a funcționat pentru mine pe Fedora 28 cu apache. Niciuna dintre regulile de rescriere de mai sus și nici cele de pe pagina CRA nu au funcționat pentru mine. Le-am adăugat la configurarea gazdei virtuale în loc să fie într-un fișier .htaccess separat. - person boerre; 25.11.2019

Dacă aveți o alternativă la index.html, asigurați-vă că în fișierul index.html aveți acest lucru:

<script>
  System.config({ baseURL: '/' });
</script>

Acest lucru poate diferi de la proiect la proiect.

person Matt Goo    schedule 03.05.2016
comment
Adăugați acest lucru în html head: ‹base href=/› - person Efe Ariaroo; 02.04.2018

Dacă utilizați firebase, tot ce trebuie să faceți este să vă asigurați că aveți o proprietate de rescriere în fișierul firebase.json din rădăcina aplicației dvs. (în secțiunea de găzduire).

De exemplu:

{ 
  "hosting": {
    "rewrites": [{
      "source":"**",
      "destination": "/index.html"
    }]    
  }
}

Sper că acest lucru salvează pe altcineva un tezaur de frustrare și timp pierdut.

Codare fericită...

Citiri suplimentare despre subiect:

https://firebase.google.com/docs/hosting/full-config#rewrites

Firebase CLI: Configurați ca o aplicație cu o singură pagină (rescrieți toate adresele URL în /index.html)

person Joshua Dyck    schedule 24.07.2018
comment
Esti o legenda - person Perniferous; 29.03.2019

Pentru cei care folosesc IIS 10, acesta este ceea ce ar trebui să faceți pentru a face acest lucru corect. Asigurați-vă că utilizați browserHistory cu aceasta. Ca referință, voi da codul pentru rutare, dar nu acesta este ceea ce contează, ceea ce contează este următorul pas după codul componentei de mai jos:

class App extends Component {
    render() {
        return (
            <Router history={browserHistory}>
                <div>
                    <Root>
                        <Switch>
                            <Route exact path={"/"} component={Home} />    
                            <Route path={"/home"} component={Home} />
                            <Route path={"/createnewproject"} component={CreateNewProject} />
                            <Route path={"/projects"} component={Projects} />
                            <Route path="*" component={NotFoundRoute} />
                        </Switch>
                    </Root>
                </div>
            </Router>
        )
    }
}
render (<App />, window.document.getElementById("app"));

Deoarece problema este că IIS primește o solicitare de la browserele client, va interpreta URL-ul ca și cum ar solicita o pagină, apoi returnează o pagină 404, deoarece nu există o pagină disponibilă. Urmează următoarele instrucțiuni:

  1. Deschideți IIS
  2. Extindeți Server, apoi deschideți folderul Sites
  3. Faceți clic pe site-ul web/aplicație
  4. Accesați paginile de eroare
  5. Deschideți elementul de stare de eroare 404 din listă
  6. În loc de opțiunea „Inserați conținut din fișierul static în răspunsul la eroare”, schimbați-o în „Executați o adresă URL pe acest site” și adăugați valoarea bară „/” la adresa URL.

Și acum va funcționa bine.

introduceți descrierea imaginii aici introduceți aici descrierea imaginii

Sper că ajută. :-)

person Martin Lloyd Jose    schedule 29.05.2018
comment
cea mai buna solutie dupa 3-4 ore de cautare. Mulţumesc mult :) - person KMR; 17.09.2020
comment
Dumnezeu sa te binecuvanteze omule - person ArtemiZ Studio; 01.06.2021

Am găsit soluția pentru SPA-ul meu cu router de reacție (Apache). Doar adăugați .htaccess

<IfModule mod_rewrite.c>

  RewriteEngine On
  RewriteBase /
  RewriteRule ^index\.html$ - [L]
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteCond %{REQUEST_FILENAME} !-l
  RewriteRule . /index.html [L]

</IfModule>

sursă: https://gist.github.com/alexsasharegan/173878f9d67049fa7136049>4540000000000000000000000000000000000000000000000000

person Sasha Ignashevich    schedule 20.01.2019

Nu folosesc încă redarea pe partea serverului, dar am întâlnit aceeași problemă ca OP, unde Link părea să funcționeze bine de cele mai multe ori, dar nu a reușit când aveam un parametru. Voi documenta soluția mea aici pentru a vedea dacă ajută pe cineva.

Jsx-ul meu principal conține asta:

<Route onEnter={requireLogin} path="detail/:id" component={ModelDetail} />

Acest lucru funcționează bine pentru primul link de potrivire, dar când :id se modifică în expresiile <Link> imbricate pe pagina de detalii a modelului respectiv, adresa URL se modifică în bara de browser, dar conținutul paginii nu s-a modificat inițial pentru a reflecta modelul legat.

Problema a fost că am folosit props.params.id pentru a seta modelul în componentDidMount. Componenta este montată doar o dată, așa că acest lucru înseamnă că primul model este cel care se lipește pe pagină, iar Link-urile ulterioare schimbă recuzita, dar lasă pagina neschimbată.

Setarea modelului în starea componentei atât în ​​componentDidMount, cât și în componentWillReceiveProps (unde se bazează pe următoarele elemente de recuzită) rezolvă problema și conținutul paginii se modifică pentru a reflecta modelul dorit.

person Paul Whipp    schedule 12.09.2016
comment
Ar putea fi mai bine să utilizați constructorul de componente (care are și acces la props) i.s.o. componentDidMount dacă doriți vreodată să încercați redarea pe partea serverului. Deoarece componentDidMount este apelat doar în browser. Scopul este de a face lucruri cu DOM, cum ar fi atașarea ascultătorilor de evenimente la body etc. pe care nu le puteți face în render. - person Stijn de Witt; 20.12.2016

Acest subiect este puțin vechi și rezolvat, dar aș dori să vă sugerez o soluție simplă, clară și mai bună. Funcționează dacă utilizați un server web.

Fiecare server web are capacitatea de a redirecționa utilizatorul către o pagină de eroare în cazul http 404. Pentru a rezolva această problemă, trebuie să redirecționați utilizatorul către pagina de index.

Dacă utilizați serverul de bază Java (tomcat sau orice server de aplicații java), soluția ar putea fi următoarea:

web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">

    <!-- WELCOME FILE LIST -->
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>

    <!-- ERROR PAGES DEFINITION -->
    <error-page>
        <error-code>404</error-code>
        <location>/index.jsp</location>
    </error-page>

</web-app>

Exemplu:

  • GET http://example.com/about
  • Serverul web aruncă http 404 deoarece această pagină nu există pe partea serverului
  • configurația paginii de eroare spune serverului care trimite pagina index.jsp înapoi utilizatorului
  • apoi JS va face restul lucrării din partea clientului, deoarece adresa URL din partea clientului este încă http://example.com/about.

Asta este, nu mai e nevoie de magie :)

person zappee    schedule 15.01.2017
comment
Asta a fost minunat! Folosesc serverul Wildfly 10.1 și am făcut această actualizare pentru fișierul meu web.xml, cu excepția faptului că aveam locația setată doar la „/”. Acest lucru se datorează faptului că în codul meu de reacție am folosit istoricul browserului astfel: const browserHistory = useRouterHistory(createHistory)({ basename: '/<appname>' }); - person Chuck L; 02.06.2017
comment
Ești sigur că acest lucru nu afectează SEO? Dați un statut 404 paginilor care există de fapt. Este posibil ca utilizatorul să nu realizeze niciodată acest lucru, dar roboții acordă multă atenție, de fapt atât de mult, încât nu vă vor zgâria pagina. - person subharb; 15.12.2017

Dacă utilizați Express sau un alt cadru în backend , puteți adăuga configurația similară ca mai jos și puteți verifica calea publică Webpack în configurație, ar trebui să funcționeze bine chiar și la reîncărcare dacă utilizați BrowserRouter

expressApp.get('/*', (request, response) => {
    response.sendFile(path.join(__dirname, '../public/index.html'));
});
person neeraj-dixit27    schedule 09.03.2018
comment
aceasta este cea mai simpla solutie. rețineți că această rută ar trebui să meargă după orice alte rute, deoarece este o captură pe toate - person dcsan; 14.02.2020

Remedierea erorii „nu se poate GET /URL” la reîmprospătare sau la apelarea directă a adresei URL.

Configurați webpack.config.js pentru a vă aștepta la legătura dată rutele ca acesta.

module.exports = {
  entry: './app/index.js',
  output: {
       path: path.join(__dirname, '/bundle'),
       filename: 'index_bundle.js',
       publicPath: '/'
  },
person Lalit Tyagi    schedule 19.12.2018

poți încerca să citești toate acestea, deși nu sunt ale mele:

https://www.andreasreiterer.at/fix-browserrouter-on-apache/

Remedierea rutei aplicației Acum iată cum să remediați în sfârșit rutarea. Pentru a-i spune lui Apache să redirecționeze cererile către index.html unde se află aplicația noastră, trebuie să modificăm fișierul .htaccess. Dacă nu există încă un astfel de fișier în dosarul aplicației dvs., creați-l.

Apoi asigurați-vă că ați introdus acele 4 linii care vă vor face ca rutarea să funcționeze în mod magic.

Options -MultiViews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.html [QSA,L]

După ce punem acel fișier .htaccess în același director cu index.html, Apache va redirecționa fiecare cerere nouă direct către aplicația dvs.

Bonus: implementarea aplicației React într-un subdirector

Dacă implementați aplicația într-un subdirector, deci este accesibilă, de ex. prin https://myapp.com/the-app, veți observa în curând că există un alt problema. Fiecare clic către o rută nouă va transforma adresa URL în ceva de genul https://myapp.com/route-abc – care se va rupe din nou după o reîncărcare. Dar există o soluție simplă pentru asta:

BrowserRouter are o propă numită basename unde puteți specifica calea subdirectorului:

From now on, each Route like /contacts will result in an URL like http://myapp.com/the-app/contacts.

person Rishabh Jain    schedule 14.10.2019
comment
Aceasta este o soluție foarte simplă pentru cei care doresc să își execute CRA dintr-un director diferit. Folosesc react-router-dom, așa că a trebuit să includ basename pe <BrowserRouter />. Dar această soluție simplă vă va economisi mult timp. Vă mulțumim pentru această contribuție! - person Josh Cronkhite; 17.09.2020
comment
Mulțumiri. Soluția ta îmi economisește timp. :) - person Adnan Ahmad; 18.11.2020
comment
Ma bucur ca te-am putut ajuta.. :) - person Rishabh Jain; 09.12.2020

Folosirea HashRouter a funcționat pentru mine și cu Redux, pur și simplu înlocuiți:

import {
  Router //replace Router
} from "react-router-dom";

ReactDOM.render(
    <LocaleProvider locale={enUS}>
    <Provider store={Store}>
        <Router history={history}> //replace here saying Router
            <Layout/>
        </Router>
    </Provider>
</LocaleProvider>, document.getElementById("app"));
registerServiceWorker();

to:

import {
  HashRouter //replaced with HashRouter
} from "react-router-dom";

ReactDOM.render(
    <LocaleProvider locale={enUS}>
    <Provider store={Store}>
        <HashRouter history={history}> //replaced with HashRouter
            <Layout/>
        </HashRouter>
    </Provider>
</LocaleProvider>, document.getElementById("app"));
registerServiceWorker();
person Alireza    schedule 24.03.2020

Dacă utilizați comanda create-react-app,

pentru a genera o aplicație react, atunci package.json trebuie să aibă o modificare pentru a rula corect producția React SPA într-un browser. Deschideți package.json și adăugați următorul segment de cod la acesta,

"start": "webpack-dev-server --inline --content-base . --history-api-fallback"

Aici cea mai importantă parte este --history-api-fallback pentru a activa istoricul apel înapoi API.

Uneori, veți primi o eroare 404 dacă utilizați Spring sau orice alt API back-end. Deci, într-o astfel de situație, trebuie să aveți un controler în back-end pentru a redirecționa orice solicitare (doriți) către fișierul index.html pentru a fi gestionat de react-router. În continuare, demonstrează un exemplu de controler scris folosind spring.

@Controller
public class ForwardingController {
    @RequestMapping("/<any end point name>/{path:[^\\.]+}/**")
    public String forward(HttpServletRequest httpServletRequest) {
        return "forward:/";
    }
}

de exemplu, dacă luăm un punct final REST API back-end ca abc (http://localhost:8080/abc/**), orice solicitare care vine la acel punct final va redirecționa către aplicația react (fișier index.html) și react- routerul se va ocupa de aceste postfaze.

person Malinda    schedule 30.01.2020
comment
De asemenea, puteți adăuga mai multe mapări ca aceasta: @RequestMapping({/myurl1/**, /myurl2/**}) - person Craigo; 17.12.2020

În cazul în care, cineva este aici în căutarea unei soluții pentru React JS SPA cu Laravel. Răspunsul acceptat este cea mai bună explicație a motivului pentru care apar astfel de probleme. După cum sa explicat deja, trebuie să configurați atât partea client, cât și partea serverului. În șablonul blade, includeți fișierul js inclus, asigurați-vă că utilizați URL facade astfel

<script src="{{ URL::to('js/user/spa.js') }}"></script>

În traseele dvs., asigurați-vă că adăugați acest lucru la punctul final principal unde se află șablonul blade. De exemplu,

Route::get('/setting-alerts', function () {
   return view('user.set-alerts');
});

Cele de mai sus este punctul final principal pentru șablonul lamă. Acum adăugați și un traseu opțional,

Route::get('/setting-alerts/{spa?}', function () {
  return view('user.set-alerts');
});

Problema care se întâmplă este că mai întâi se încarcă șablonul blade, apoi routerul de reacție. Deci, când încărcați '/setting-alerts', se încarcă html și js. Dar când încărcați '/setting-alerts/about', se încarcă mai întâi pe partea serverului. Deoarece pe partea serverului, nu există nimic în această locație, se întoarce negăsit. Când aveți acel router opțional, acesta încarcă aceeași pagină și routerul react se încarcă, apoi react loader decide ce componentă să afișeze. Sper că acest lucru vă ajută.

person Koushik Das    schedule 14.11.2017
comment
Este posibil să se încarce la un singur URI exact pe server, apoi serverul să facă o redirecționare către React? De exemplu, când încărc /user/{userID}, trebuie doar să returnez o vizualizare HTML /user universală, să aduc ID-ul și să-l apelez folosind AJAX sau axios. Este posibil să faci asta? sunt prietenosi cu SEO? - person Ryuujo; 22.02.2019
comment
Folosesc acest cod pentru SPA-urile mele cu un backend Laravel: Route::any('{any?}', 'MyController@index'); Se potrivește cu orice rută și îl transmite către SPA - person Felix Geenen; 08.09.2020

Pe măsură ce folosesc .Net Core MVC, ceva de genul acesta m-a ajutat:

    public class HomeController : Controller
    {
        public IActionResult Index()
        {
            var url = Request.Path + Request.QueryString;
            return App(url);
        }

        [Route("App")]
        public IActionResult App(string url)
        {
            return View("/wwwroot/app/build/index.html");
        }
   }

Practic, în partea MVC, toate rutele care nu se potrivesc se vor încadra în Home/Index așa cum a specificat în startup.cs. În Index este posibil să obțineți adresa URL a solicitării originale și să o transmiteți oriunde este necesar.

startup.cs

        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");

            routes.MapSpaFallbackRoute(
                name: "spa-fallback",
                defaults: new { controller = "Home", action = "Index" });
        });
person Elnoor    schedule 11.03.2019
comment
Dacă API-ul web este separat de aplicație, cum veți gestiona acest lucru? - person Dayán Ruiz; 01.05.2019
comment
@dayanrr91 dacă proiectul dvs. are API web, oricum nu veți avea nevoie de rutare pe server. Și reacționați-ruterul cred că ar trebui să citească adresa URL și să facă rutarea corespunzătoare. Nimic nu ar trebui să-l blocheze - person Elnoor; 01.05.2019
comment
comentariul tău este foarte apreciat, dar apoi am o întrebare, tocmai am adăugat HashRouter, dar acum, când intru manual la orice URL, acesta va redirecționa către componenta mea de acasă în loc să redirecționeze către componenta mea acasă și apoi către componenta pe care încercam să o fac intrând, există vreo soluție pentru asta? - person Dayán Ruiz; 01.05.2019
comment
@dayanrr91 chiar nu am idee, nu am încercat niciodată hashrouter, dar cred că ar trebui să aibă legătură cu codul tău. Modul în care funcționează hashrouter-ul ar trebui să fie similar cu browserrouter-ul. De asemenea, tocmai am testat aici în acest sandbox, funcționează bine codesandbox.io/s/25okp1mny, testați url 25okp1mny.codesandbox.io/#/roster/5 - person Elnoor; 01.05.2019

Dacă găzduiți în IIS; Adăugarea acestui lucru la configurația mea web mi-a rezolvat problema

<httpErrors errorMode="Custom" defaultResponseMode="ExecuteURL">
    <remove statusCode="500" subStatusCode="100" />
    <remove statusCode="500" subStatusCode="-1" />
    <remove statusCode="404" subStatusCode="-1" />
    <error statusCode="404" path="/" responseMode="ExecuteURL" />
    <error statusCode="500" prefixLanguageFilePath="" path="/error_500.asp" responseMode="ExecuteURL" />
    <error statusCode="500" subStatusCode="100" path="/error_500.asp" responseMode="ExecuteURL" />
</httpErrors>

Puteți face configurații similare pentru orice alt server

person Barny    schedule 26.04.2017

Pentru aceia dintre voi care sunteți aici pentru că încercați să difuzați o aplicație react dintr-un director virtual IIS (nu rădăcina unui site web), atunci aceasta poate fi pentru dvs.

Când configurați redirecționările dvs. „/” nu va funcționa de la sine, pentru mine avea nevoie și de numele directorului virtual acolo. Iată cum arăta configurația mea web:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <defaultDocument>
            <files>
                <remove value="default.aspx" />
                <remove value="iisstart.htm" />
                <remove value="index.htm" />
                <remove value="Default.asp" />
                <remove value="Default.htm" />
            </files>
        </defaultDocument>
        <rewrite>
            <rules>
                <rule name="React Routes" stopProcessing="true">
                    <match url=".*" />
                    <conditions logicalGrouping="MatchAll">
                        <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
                        <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
                        <add input="{REQUEST_URI}" pattern="^/(api)" negate="true" />
                    </conditions>
                    <action type="Rewrite" url="/YOURVIRTUALDIRECTORYNAME/" />
                </rule>
            </rules>
        </rewrite>
        <directoryBrowse enabled="false" />
        <httpErrors errorMode="Custom" defaultResponseMode="ExecuteURL">
            <remove statusCode="500" subStatusCode="100" />
            <remove statusCode="500" subStatusCode="-1" />
            <remove statusCode="404" subStatusCode="-1" />
            <remove statusCode="403" subStatusCode="18" />
            <error statusCode="403" subStatusCode="18" path="/YOURVIRTUALDIRECTORYNAME/" responseMode="ExecuteURL" />
            <error statusCode="404" path="/YOURVIRTUALDIRECTORYNAME/" responseMode="ExecuteURL" />
            <error statusCode="500" prefixLanguageFilePath="" path="/YOURVIRTUALDIRECTORYNAME/" responseMode="ExecuteURL" />
            <error statusCode="500" subStatusCode="100" path="/YOURVIRTUALDIRECTORYNAME/" responseMode="ExecuteURL" />
        </httpErrors>
    </system.webServer>
</configuration>

Pe lângă fișierul web.config, aplicația react are nevoie de câteva modificări:

în package.json trebuie să adăugați o intrare „pagină de pornire”:

{
  "name": "sicon.react.crm",
  "version": "0.1.0",
  "private": true,
  "homepage": "/YOURVIRTUALDIRECTORYNAME/",
  "dependencies": {
...

Am adăugat numele de bază la obiectul istoric al browserului meu pe care îl transmit în router pentru a avea acces la istorie:

import  {createBrowserHistory } from 'history';

export default createBrowserHistory({
    //Pass the public URL as the base name for the router basename: process.env.PUBLIC_URL
});

Am adăugat și această proprietate pe routerul meu React în App.js:

  <Router history={history} basename={process.env.PUBLIC_URL}>

În cele din urmă, în index.html am adăugat următoarea filă deasupra etichetei „title”.

  <base href="%PUBLIC_URL%/">

s-ar putea ca unii pași să fie nevoie de notă, dar acest lucru pare să fi făcut treaba pentru mine. Nu știu cum să-l configurez să ruleze fie în rădăcina unui site, fie într-un director virtual fără o recompilare, deși pagina de pornire din package.json nu poate fi schimbată după o construcție, din câte știu eu.

person WraithNath    schedule 19.07.2020
comment
Ultimele două linii de cod din postarea ta m-au salvat. Mulțumiri! basename în <Router /> și <base /> în index.html. - person Craig Howell; 28.04.2021
comment
@CraigHowell - Mă bucur că a ajutat! Am revenit la această postare să-mi reamintesc și mie! - person WraithNath; 30.04.2021

Răspunsuri cu adevărat minunate deja!! Dar dacă găzduiți folosind nginx și aveți nevoie de o remediere rapidă... adăugați următoarea linie la configurația dvs. nginx în blocul de locație

location / {
  try_files $uri /index.html;
}
person BeK    schedule 18.03.2021

Adăugarea mai multor informații la răspunsul lui Joshua Dyck.

Dacă utilizați Firebase și doriți să utilizați atât ruta rădăcină, cât și ruta sub-director, trebuie să adăugați următorul cod în firebase.json:

{
  "hosting": {
    "rewrites": [
      {
        "source": "*",
        "destination": "/index.html"
      },
      {
        "source": "/subdirectory/**",
        "destination": "/subdirectory/index.html"
      }
    ]
  }
}

Exemplu:

Construiți un site web pentru un client. Doriți ca proprietarul site-ului web să adauge informații în https://your.domain.com/management în timp ce utilizatorii site-ului web vor naviga la https://your.domain.com.

În acest caz, fișierul dvs. firebase.json va arăta astfel:

{
  "hosting": {
    "rewrites": [
      {
        "source": "*",
        "destination": "/index.html"
      },
      {
        "source": "/management/**",
        "destination": "/management/index.html"
      }
    ]
  }
}
person neomib    schedule 12.03.2019

Folosesc WebPack, am avut aceeași problemă Soluție => În fișierul server.js

const express = require('express');
const app = express();

app.use(express.static(path.resolve(__dirname, '../dist')));
  app.get('*', function (req, res) {
    res.sendFile(path.resolve(__dirname, '../dist/index.html'));
    // res.end();
  });

De ce nu Aplicația mea nu se redă după reîmprospătare?

person Vishal Singh    schedule 19.02.2019
comment
Asta a făcut-o pentru mine! Inițial am avut res.sendFile(path.JOIN(publicPath, index.html)); Am schimbat join to resolved ca în exemplul de mai sus la: res.sendFile(path.resolve(./dist, index.html)); De asemenea, mă jucam cu __dirname, dar nu puteam să-l înțeleg sau să-l fac să funcționeze, așa că am copiat manual în ./dist, deoarece de aici este servit index.html-ul meu. De asemenea, am declarat-o așa mai devreme: app.use(express.static(./dist)); - person logixplayer; 10.05.2020

Am folosit abordarea de gestionare 404 a expresului

// path to the static react build directory    
const frontend = path.join(__dirname, 'react-app/build');

// map the requests to the static react build directory
app.use('/', express.static(frontend));

// all the unknown requests are redirected to the react SPA
app.use(function (req, res, next) {
    res.sendFile(path.join(frontend, 'index.html'));
});

Funcționează ca un farmec. O demonstrație live este site-ul nostru

person Zameer Ansari    schedule 22.09.2019
comment
asta a funcționat pentru mine, mulțumesc pentru răspuns! - person Apostolos; 13.05.2021

Am rezolvat această problemă schimbând webpack.config.js.

noua mea configurație arată astfel:

Înainte de :

output: {
  path: path.join(__dirname, '/build/static/js'),
  filename: 'index.js'
},


devServer: {
  port: 3000
}

După:

output: {
  path: path.join(__dirname, '/build/static/js'),
  filename: 'index.js',
  publicPath: '/'
},


devServer: {
  historyApiFallback: true,
  port: 3000
}
person Sunil Kumar Singh    schedule 29.04.2020

În cazul în care îl rulați pe un Google Bucket, soluția simplă pentru aceasta este să luați în considerare „index.html” pentru Pagina de eroare (404 nu a fost găsită).

To do so:

  1. În lista de găleți, găsiți găleata pe care ați creat-o.
  2. Faceți clic pe meniul Bucket overflow (...) asociat cu bucket și selectați Editați configurația site-ului web.
  3. În dialogul de configurare a site-ului web, specificați și pagina principală ca pagină de eroare.
person Sansei    schedule 16.07.2020
comment
Acest lucru nu funcționează pentru mine - person Md. Parvez Alam; 16.12.2020

Folosind Express pe backend și React pe front-end (fără react-create-app) cu atingere/router, este afișată componenta corectă de reacție a traseului de acoperire/router, iar linkul de meniu este setat la stilul activ atunci când apăsați enter în bara de adrese de exemplu http://localhost:8050/pages. Vă rugăm să verificați mai jos sau direct la depozitul meu https://github.com/nickjohngray/staticbackeditor, toate codul este acolo.

Pachet web:

Configurați proxy. Acest lucru permite oricăror apeluri din portul 3000 (React) să apeleze serverul, inclusiv apelul pentru a obține index.html sau orice altceva din bara de adrese atunci când este apăsată tasta Enter. permite, de asemenea, apeluri către ruta API, pentru a obține date JSON

ca await axios.post('/api/login', {email, pwd})

devServer: {
    port: 3000,
    open: true,
    proxy: {
      '/': 'http://localhost:8050',
    }
  }

Configurați rute expres

app.get('*', (req, res) => {
    console.log('sending index.html')
    res.sendFile(path.resolve('dist', 'index.html'))

});

Aceasta se va potrivi cu orice solicitare de la react, doar returnează pagina index.html, care se află în folderul meu dist, această pagină, desigur, are o aplicație react cu o singură pagină. (rețineți că orice alte rute ar trebui să apară deasupra acesteia, în cazul meu, acestea sunt rutele mele API)

Rute de reacție

<Router>
    <Home path="/" />
    <Pages path="pages"/>
    <ErrorPage path="error"/>
    <Products path="products"/>
    <NotFound default />
</Router>

Aceste rute sunt definite în componenta mea Layout care va încărca componenta corespunzătoare atunci când calea se potrivește.

Constructorul React Layout

 constructor(props) {
        super(props);


        this.props.changeURL({URL: globalHistory.location.pathname});
}

constructorul Layout este apelat de îndată ce se încarcă. Aici îmi numesc acțiunea redux changeURL pe care o ascultă meniul, astfel încât să poată evidenția elementul corect de meniu, ca mai jos:

Codul de meniu

<nav>
    {this.state.links.map( (link) =>
    <Link className={this.getActiveLinkClassName(link.path) } to={link.path}> 
      {link.name}
    </Link>)}            
</nav>
person nick    schedule 08.08.2020

În cazul meu, adresa URL nu se încărca când foloseam parametrul în ea.

Ca o remediere rapidă, adaug <base href="<yourdomain/IP>"></base> sub eticheta fișierului index.html în folderul de compilare.

Și asta tocmai mi-a rezolvat problema.

person Diwakar Prasad    schedule 02.02.2021

Am avut aceeași problemă și aceasta soluția a funcționat pentru noi..

Fundal:

Găzduim mai multe aplicații pe același server. Când am reîmprospăta, serverul nu ar înțelege unde să caute indexul nostru în folderul dist pentru respectiva aplicație. Link-ul de mai sus vă va duce la ceea ce a funcționat pentru noi... Sper că acest lucru vă va ajuta, deoarece am petrecut destul de multe ore pentru a găsi o soluție pentru nevoile noastre.

Noi folosim:

package.json

"dependencies": {
"babel-polyfill": "^6.23.0",
"ejs": "^2.5.6",
"express": "^4.15.2",
"prop-types": "^15.5.6",
"react": "^15.5.4",
"react-dom": "^15.5.4",
"react-redux": "^5.0.4",
"react-router": "^3.0.2",
"react-router-redux": "^4.0.8",
"redux": "^3.6.0",
"redux-persist": "^4.6.0",
"redux-thunk": "^2.2.0",
"webpack": "^2.4.1"
}

meu webpack.config.js

webpack.config.js

/* eslint-disable */
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const babelPolyfill = require('babel-polyfill');
const HTMLWebpackPluginConfig = new HtmlWebpackPlugin({
  template: __dirname + '/app/views/index.html',
  filename: 'index.html',
  inject: 'body'
});

module.exports = {
  entry: [
    'babel-polyfill', './app/index.js'
  ],
  output: {
    path: __dirname + '/dist/your_app_name_here',
    filename: 'index_bundle.js'
  },
  module: {
    rules: [{
      test: /\.js$/,
      loader: 'babel-loader',
      query : {
          presets : ["env", "react", "stage-1"]
      },
      exclude: /node_modules/
    }]
  },
  plugins: [HTMLWebpackPluginConfig]
}

indexul meu.js

index.js

import React from 'react'
import ReactDOM from 'react-dom'
import Routes from './Routes'
import { Provider } from 'react-redux'
import { createHistory } from 'history'
import { useRouterHistory } from 'react-router'
import configureStore from './store/configureStore'
import { syncHistoryWithStore } from 'react-router-redux'
import { persistStore } from 'redux-persist'

const store = configureStore();

const browserHistory = useRouterHistory(createHistory) ({
  basename: '/your_app_name_here'
})
const history = syncHistoryWithStore(browserHistory, store)

persistStore(store, {blacklist: ['routing']}, () => {
  console.log('rehydration complete')
})
// persistStore(store).purge()


ReactDOM.render(
    <Provider store={store}>
      <div>
        <Routes history={history} />
      </div>
    </Provider>,
  document.getElementById('mount')
)

aplicația mea.js

var express = require('express');
var app = express();

app.use(express.static(__dirname + '/dist'));
// app.use(express.static(__dirname + '/app/assets'));
app.set('views', __dirname + '/dist/your_app_name_here');
app.engine('html', require('ejs').renderFile);
app.set('view engine', 'html');

app.get('/*', function (req, res) {
    res.render('index');
});

app.listen(8081, function () {
  console.log('MD listening on port 8081!');
});
person J. Parrish    schedule 05.05.2017

Îmi place acest mod de a o manipula. Încercați să adăugați: yourSPAPageRoute/* pe partea de server pentru a scăpa de această problemă.

Am urmat această abordare deoarece nici măcar API-ul nativ HTML5 History nu acceptă redirecționarea corectă la reîmprospătarea paginii (din câte știu eu).

Notă: răspunsul selectat a abordat deja acest lucru, dar încerc să fiu mai specific.

Rută expres

Test - History API Am testat și am vrut doar să distribui asta.

Sper ca ajuta.

person Rehan    schedule 05.12.2018

Să presupunem că aveți următoarea definiție a rutei de acasă

<Route exact path="/" render={routeProps => (
   <Home routeProps={routeProps}/>
)}/>

{/*optional catch-all router */}
<Route render={routeProps => (
       <div><h4>404 not found</h4></div>
)}/>

La componenta dvs. Acasă, puteți intercepta cererea la evenimentul ComponentWillMount,

const searchPath = this.props.routeProps.location.search;

if (searchPath){
    this.props.routeProps.history.push("/" + searchPath.replace("?",""));
}
else{
    /*.... originally Home event */
}

Acum, în loc să apelați /joblist la adresa URL, puteți solicita /?joblist, iar Componenta va redirecționa automat solicitarea către /joblist (rețineți semnul de întrebare suplimentar din cale)

person user2674595    schedule 09.07.2019

Dacă veniți aici și utilizați apache și nu aveți un fișier .htaccess, acesta este un fișier de configurare care a funcționat pentru mine:

sites-enabled/somedomain.com.conf

<VirtualHost *:80>
    ServerName somedomain.com
    ServerAlias *.somedomain.com
    DocumentRoot /www/somedomain.com/build

    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule . /www/somedomain.com/build/index.html [L,NC,QSA]

</VirtualHost>
person DevB2F    schedule 16.07.2019

Soluție pentru Preact cu preact-router

Funcționează cu reîmprospătare și acces direct

Pentru cei care descoperă acest lucru prin Google, iată o demonstrație a istoricului preact-router + hash:

const { h, Component, render } = preact; /** @jsx h */
const { Router } = preactRouter;
const { createHashHistory } = History;
const App = () => (
    <div>
        <AddressBar />

        <Router history={createHashHistory()}>
            <div path="/">
                <p>
                    all paths in preact-router are still /normal/urls.
                    using hash history rewrites them to /#/hash/urls
                </p>
                Example: <a href="/ro/page2">page 2</a>
            </div>
            <div path="/page2">
                <p>Page Two</p>
                <a href="/ro/">back to home</a><br/>
            </div>
        </Router>
    </div>
);

jsfiddle

person keemor    schedule 05.10.2017

Iată o soluție frontală pe care am descoperit-o, care nu necesită modificarea nimic pe server.

Să presupunem că site-ul dvs. este mysite.com și aveți o rută de reacție către mysite.com/about. În index.js, unde montați componenta dvs. de nivel superior, puteți pune un alt Router precum:

ReactDOM.render(
<Router>
    <div>
        <Route exact path="/" component={Home} />
        <Route exact path="/about"
            render={(props) => <Home {...props} refreshRout={"/about"}/>}
        />
    </div>
</Router>,

Presupun că aveți routerul original situat undeva sub componenta de nivel superior în DOM-ul virtual. De asemenea, trebuie să prindeți adresa URL în .urls-ul dvs. dacă utilizați Django, cum ar fi:

urlpatterns = [
       path('about/', views.index),
]

Totuși, aceasta va depinde de ce backend utilizați. Solicitarea mysite/about vă va duce în index.js (unde montați componenta de nivel superior) unde puteți utiliza prop de randare a Rutei, mai degrabă decât prop de componentă, și transmiteți „/about” ca prop la, în acest exemplu, componenta Acasă.

În Acasă, fie în componentDidMount() fie în cârligul useEffect(), faceți:

useEffect() {   
   //check that this.props.refreshRoute actually exists before executing the 
   //following line    
   this.props.history.replace(this.props.refreshRoute);
}

Am presupus că componenta dvs. Acasă redă ceva de genul:

<Router>
   <Route exact path="/" component={SomeComponent} />
   <Route path="/about" component={AboutComponent} />
</Router>

Credit către (Trimite elemente de recuzită către o componentă redată de React Router) pentru a transmite elemente de recuzită componentelor din Routes.

person Stevie    schedule 28.07.2019

Folosesc .Net Core 3.1 și tocmai am adăugat extensia MapFallbackToController:

Startup.cs

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");

        endpoints.MapFallbackToController("Index", "Home");
    });
person Sergio    schedule 08.05.2020

Cealaltă modalitate de a solicita date, chiar dacă direcționați imediat către adrese URL, este să faceți ca fiecare componentă să aibă o metodă care apelează la acei ultimi parametri precum /about/test și apoi la furnizorul dvs. de stat aveți funcția care se conectează la componenta cu care doriți să solicitați date

person Vince    schedule 04.06.2020

Folosesc modul React.js + Webpack. Am adăugat parametrul --history-api-fallback în fișierul package.json. Apoi, reîmprospătarea paginii funcționează corect. Fiecare când schimb codul, pagina web se reîmprospătează automat.

"scripts": {
  "start": "rimraf build && cross-env NODE_ENV='development' webpack --mode development && cross-env NODE_ENV=development webpack-dev-server --history-api-fallback",
  ...
}
person NinjaDev    schedule 12.08.2020

Știu că la această întrebare s-a răspuns până la moarte, dar nu rezolvă problema în care doriți să utilizați routerul browserului cu trecerea proxy, unde nu puteți utiliza root.

Pentru mine solutia este destul de simpla.

spuneți că aveți o adresă URL care indică un port.

location / {
  proxy_pass http://127.0.0.1:30002/;
  proxy_set_header    Host            $host;
  port_in_redirect    off;
}

iar acum, din cauza browserului, căile secundare ale routerului sunt întrerupte. Cu toate acestea, știți care sunt căile secundare.

Soluția la asta? Pentru calea secundară /contact

# just copy paste.
location /contact/ {
  proxy_pass http://127.0.0.1:30002/;
  proxy_set_header    Host            $host;
}

Nimic altceva din ce am încercat funcționează, dar această soluție simplă funcționează ca un farmec al naibii.

person danieltan95    schedule 09.11.2020

Mă confruntam cu această problemă în Electron când foloseam React pentru front-end și react-router-dom pentru rutare. Am înlocuit BrowserRouter cu HashRouter și s-a remediat. Iată un exemplu simplu

import {
  HashRouter as Router,
  Switch,
  Route,
} from "react-router-dom";
person Sanan Ali    schedule 03.06.2021
comment
nu este nevoie să folosesc HashRouter, am soluția pentru asta, m-am confruntat recent cu această problemă într-un proiect, probabil că voi scrie un răspuns mai târziu când voi avea timp - person Inzamam Malik; 10.07.2021
comment
sigur, as vrea sa stiu solutia ta. - person Sanan Ali; 12.07.2021

HashRouter va fi o implementare ușoară,

import {HashRouter as Router,Switch,Route,Link} from 'react-router-dom';


  function App() {
  return (
    <Router>
        <Switch>
          <Route path="/" exact component={InitialComponent} />
          <Route path="/some" exact component={SomeOtherComponent} />
        </Switch>
      </Router>
  );
}

Va fi ceva de genul acesta în browser - http:localhost:3000/#/ , http:localhost:3000/#/some

person lakjeewa Wijebandara    schedule 10.07.2021

Este destul de simplu când nu ați primit eroarea 403 după reîmprospătarea componentei dom. doar adăugați această linie în configurația pachetului dvs. web, „historyApiFallback: true”. asta îmi salvează toată ziua.

person praveenkumar s    schedule 02.01.2018

Router complet cu exemplu (React Router v4):

Exemplu de lucru Exemplu Consultați proiectul de mai jos.

react-router-4-example

După descărcare
1.) „npm install” în cmd pentru a instala proiectul
2.) „npm start” pentru a porni aplicația ta react

Notă: aveți nevoie de software-ul Node js pentru a rula în Windows. Mac OS are un nod implicit.

Noroc

person Muthu Kumar    schedule 29.01.2019