Adresy URL routera React nie działają podczas ręcznego odświeżania lub pisania

Używam React-routera i działa dobrze, gdy klikam przyciski linków, ale kiedy odświeżam stronę internetową, nie ładuje tego, czego chcę.

Na przykład jestem w localhost/joblist i wszystko jest w porządku, ponieważ dotarłem tutaj, naciskając link. Ale jeśli odświeżę stronę, otrzymam:

Cannot GET /joblist

Domyślnie tak nie działało. Początkowo miałem adres URL jako localhost/#/ i localhost/#/joblist i działały idealnie. Ale nie lubię tego rodzaju adresu URL, więc próbując wymazać ten #, napisałem:

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

Ten problem nie występuje z localhost/, ten zawsze zwraca to, czego chcę.

EDYTUJ: ta aplikacja jest jednostronicowa, więc /joblist nie musi prosić o nic serwera.

EDIT2: Cały mój 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 źródło
comment
chyba że użyjesz htaccess do załadowania głównej strony z trasami koncertowymi i powiesz routerowi, aby używał location.pathname, to nie zadziała..   -  person CJT3    schedule 20.01.2015
comment
Jak wymazałeś ten symbol #? Dziękuję Ci!   -  person SudoPlz    schedule 06.06.2015
comment
Jeśli hostujesz aplikację React w zasobniku S3, możesz po prostu ustawić dokument błędu na index.html. Dzięki temu index.html zostanie trafiony bez względu na wszystko.   -  person Trevor Hutto    schedule 30.07.2016
comment
W moim przypadku działa dobrze w systemie Windows, ale nie w Linuksie   -  person Ejaz Karim    schedule 04.12.2017
comment
To jest odniesienie, które pomogło rozwiązać mój problem: github.com/facebook/create-react-app/blob/master/packages/   -  person jimbotron    schedule 10.07.2018


Odpowiedzi (52)


Patrząc na komentarze do zaakceptowanej odpowiedzi i ogólny charakter tego pytania („nie działa”), pomyślałem, że to może być dobre miejsce na ogólne wyjaśnienia dotyczące kwestii tutaj poruszanych. Tak więc ta odpowiedź ma służyć jako podstawowe informacje / opracowanie na temat konkretnego przypadku użycia PO. Proszę o wyrozumiałość.

Po stronie serwera a po stronie klienta

Pierwszą ważną rzeczą do zrozumienia jest to, że obecnie istnieją 2 miejsca, w których adres URL jest interpretowany, podczas gdy w „dawnych czasach” było tylko jedno. W przeszłości, gdy życie było proste, niektórzy użytkownicy wysyłali żądanie http://example.com/about do serwera, który sprawdzał część ścieżki adresu URL, ustalał, że użytkownik żąda strony z informacjami, a następnie odsyła tę stronę.

Dzięki routingowi po stronie klienta, który zapewnia React-Router, sprawy są mniej proste. Początkowo klient nie ma jeszcze załadowanego kodu JS. Tak więc pierwsze żądanie zawsze będzie skierowane do serwera. Spowoduje to zwrócenie strony zawierającej znaczniki skryptu potrzebne do załadowania React i React Router itp. Faza 2 rozpoczyna się dopiero po załadowaniu tych skryptów. W fazie 2, gdy użytkownik kliknie na przykład link nawigacyjny „O nas”, adres URL zostanie zmieniony tylko lokalnie na http://example.com/about (jest to możliwe dzięki History API), ale nie jest wysyłane żadne żądanie do serwera. Zamiast tego React Router robi swoje po stronie klienta, określa, który widok React ma być renderowany i renderuje go. Zakładając, że twoja strona about nie musi wykonywać żadnych wywołań REST, to już zostało zrobione. Przeszedłeś z Home na O nas bez wywoływania żadnego żądania serwera.

Tak więc w zasadzie po kliknięciu łącza uruchamiany jest skrypt JavaScript, który manipuluje adresem URL w pasku adresu, bez powodowania odświeżania strony, co z kolei powoduje, że React Router wykonuje przejście strony na kliencie -strona.

Ale teraz zastanów się, co się stanie, jeśli skopiujesz i wkleisz adres URL w pasku adresu i wyślesz go e-mailem do znajomego. Twój znajomy nie wczytał jeszcze Twojej witryny. Innymi słowy, wciąż jest w fazie 1. Na jej komputerze nie działa jeszcze React Router. Jej przeglądarka wyśle ​​więc żądanie serwera do http://example.com/about.

I tu zaczynają się twoje kłopoty. Do tej pory mogłeś ujść na sucho po prostu umieszczając statyczny kod HTML w webroocie swojego serwera. Ale to dałoby 404 błędy dla wszystkich innych adresów URL na żądanie z serwera. Te same adresy URL działają dobrze po stronie klienta, ponieważ React Router wykonuje za ciebie routing, ale nie działają po stronie serwera, chyba że sprawisz, że twój serwer zrozumiał ich.

Łączenie routingu po stronie serwera i klienta

Jeśli chcesz, aby adres URL http://example.com/about działał zarówno po stronie serwera, jak i klienta, musisz skonfigurować dla niego trasy zarówno po stronie serwera, jak i klienta. Ma sens, prawda?

I tu zaczynają się twoje wybory. Rozwiązania wahają się od całkowitego ominięcia problemu, poprzez ścieżkę typu catch-all, która zwraca kod HTML ładowania początkowego, po podejście całkowicie izomorficzne, w którym zarówno serwer, jak i klient uruchamiają ten sam kod JS.

.

Całkowite ominięcie problemu: Hash History

Z Hash History zamiast Historia przeglądarki, Twój adres URL strony z informacjami będzie wyglądał mniej więcej tak: http://example.com/#/about Część po symbolu skrótu (#) nie jest wysyłana na serwer. Tak więc serwer widzi tylko http://example.com/ i wysyła stronę indeksu zgodnie z oczekiwaniami. React-Router pobierze część #/about i wyświetli właściwą stronę.

Wady:

  • „brzydkie” adresy URL
  • W tym podejściu renderowanie po stronie serwera nie jest możliwe. Jeśli chodzi o optymalizację pod kątem wyszukiwarek (SEO), Twoja witryna składa się z jednej strony, na której nie ma prawie żadnej treści.

.

Złap wszystkie

Dzięki takiemu podejściu korzystasz z historii przeglądarki, ale po prostu konfigurujesz catch-all na serwerze, który wysyła /* do index.html, skutecznie dając taką samą sytuację, jak w przypadku historii skrótów. Masz jednak czyste adresy URL i możesz później ulepszyć ten schemat bez konieczności unieważniania wszystkich ulubionych przez użytkownika.

Wady:

  • Bardziej złożony w konfiguracji
  • Nadal brak dobrego SEO

.

Hybrydowy

W podejściu hybrydowym rozwijasz scenariusz typu catch-all, dodając określone skrypty dla określonych tras. Możesz stworzyć proste skrypty PHP, które będą zwracały najważniejsze strony Twojej witryny z dołączoną treścią, aby Googlebot mógł przynajmniej zobaczyć, co jest na Twojej stronie.

Wady:

  • Jeszcze bardziej skomplikowana konfiguracja
  • Tylko dobre SEO dla tych tras, które traktujesz w szczególny sposób
  • Powielanie kodu do renderowania treści na serwerze i kliencie

.

Izomorficzny

Co się stanie, jeśli użyjemy Node JS jako naszego serwera, aby móc uruchomić ten sam kod JS na obu końcach? Teraz mamy wszystkie nasze trasy zdefiniowane w jednej konfiguracji routera React-router i nie musimy duplikować naszego kodu renderującego. To jest, że tak powiem, „święty Graal”. Serwer wysyła dokładnie takie same znaczniki, jakie otrzymalibyśmy, gdyby przejście strony miało miejsce na kliencie. To rozwiązanie optymalne z punktu widzenia SEO.

Wady:

  • Serwer musi (być w stanie) uruchamiać JS. Eksperymentowałem z Javą i.c.w. Nashorn, ale dla mnie to nie działa. W praktyce oznacza to głównie konieczność korzystania z serwera opartego na Node JS.
  • Wiele trudnych problemów środowiskowych (używanie window po stronie serwera itp.)
  • Stroma krzywa uczenia się

.

Którego powinienem użyć?

Wybierz ten, który ujdzie Ci na sucho. Osobiście uważam, że wszystko jest dość proste do skonfigurowania, więc to byłoby moje minimum. Ta konfiguracja pozwala z czasem ulepszać rzeczy. Jeśli używasz już Node JS jako platformy serwerowej, zdecydowanie zbadam tworzenie aplikacji izomorficznej. Tak, na początku jest to trudne, ale kiedy już to zrozumiesz, jest to w rzeczywistości bardzo eleganckie rozwiązanie problemu.

Więc w zasadzie dla mnie byłby to decydujący czynnik. Jeśli mój serwer działa na Node JS, byłbym izomorficzny; w przeciwnym razie wybrałbym rozwiązanie typu „catch-all” i po prostu je rozszerzyłem (rozwiązanie hybrydowe) w miarę upływu czasu i wymagań SEO.

Jeśli chcesz dowiedzieć się więcej o renderowaniu izomorficznym (zwanym również „uniwersalnym”) w React, znajdziesz kilka dobrych samouczków na ten temat:

Ponadto, aby zacząć, polecam zapoznać się z kilkoma zestawami startowymi. Wybierz taki, który pasuje do twoich wyborów dla stosu technologii (pamiętaj, że React to tylko V w MVC, potrzebujesz więcej rzeczy, aby zbudować pełną aplikację). Zacznij od przyjrzenia się tej opublikowanej przez samego Facebooka:

Lub wybierz jeden z wielu przez społeczność. Jest teraz fajna strona, która próbuje zindeksować je wszystkie:

Zacząłem od tych:

Obecnie używam domowej wersji uniwersalnego renderowania, która została zainspirowana dwoma powyższymi zestawami startowymi, ale są one już nieaktualne.

Powodzenia w Twojej misji!

person Stijn de Witt    schedule 14.04.2016
comment
Świetny post Stijn! Czy poleciłbyś zakup zestawu startowego do aplikacji Isomorphic React? Jeśli tak, czy mógłbyś podać przykład takiego, który wolisz? - person Chris; 29.04.2016
comment
@Chris Przepraszam za spóźnioną odpowiedź, byłem na wycieczce. Właściwie wypróbowałem kilka izomorficznych zestawów startowych. Dodam o tym trochę informacji w poście. - person Stijn de Witt; 06.05.2016
comment
@Stijn - To naprawdę wyjaśniło mi kilka rzeczy, dzięki. Czy możesz wyjaśnić technikę „catch-all”? Wydaje mi się to w tej chwili logicznym krokiem, ale nie jestem pewien, gdzie znaleźć więcej szczegółów na temat tego, jak to zrobić ... - person Paulos3000; 30.10.2016
comment
@Paulos3000 To zależy od tego, jakiego serwera używasz. Zasadniczo definiujesz trasę dla /* i sprawiasz, że odpowiada ona twoją stroną HTML. Trudną rzeczą jest upewnienie się, że tą trasą nie przechwytujesz żądań dotyczących plików .js i .css. - person Stijn de Witt; 30.10.2016
comment
@Paulos3000 Zobacz tutaj kilka powiązanych pytań: dla Apache/php, dla Express/js, dla J2E/Java. - person Stijn de Witt; 30.10.2016
comment
Używałbym serwera Express. Widziałem kod do tego, ale nie jestem do końca pewien, jak go zintegrować... Jak bym to zrobił na przykład z webpackiem? - person Paulos3000; 30.10.2016
comment
@Paulos3000 Express faktycznie sprawia, że ​​jest to bardzo proste. Tylko upewnij się, że dodałeś coś do tego efektu jako ostatnią obsługę: app.use('*', function(req, res, next) {res.send('<DOCTYPE html ....')}); - person Stijn de Witt; 01.11.2016
comment
...ale oczywiście, ponieważ używasz ekspresu, naprawdę powinieneś zbadać rozwiązanie izomorficzne/uniwersalne ;) - person Stijn de Witt; 01.11.2016
comment
Co ciekawe, odkąd po raz pierwszy stworzyłem tę odpowiedź, sam Facebook wprowadził zestaw startowy. Może wypróbuj ten? github.com/facebookincubator/create-react-app - person Stijn de Witt; 01.11.2016
comment
Dziękuję bardzo - to wyjaśniło aspekty kierowania do mnie, których nie udało się uzyskać w Googlingu i czytaniu oficjalnych dokumentów Reacta. Czy mogę zasugerować, abyś przesłał to ludziom z React, aby dołączyli je do ich dokumentów? - person John McGrath; 17.12.2016
comment
@JohnMcGrath Dzięki i cieszę się, że ci pomogło. Dokumentacja React Router byłaby prawdopodobnie bardziej odpowiednia. Są open source, więc możesz zaoferować to jako wkład... Może najpierw skieruj ich do tego postu i zapytaj, czy są zainteresowani? - person Stijn de Witt; 20.12.2016
comment
@Stijn de Witt To świetne wyjaśnienie i dobrze udzielone odpowiedzi na ten temat. Jednak jakie są opcje, gdy Twoja aplikacja może być obsługiwana w podkatalogu (na przykład przez iis). Np.: domena/appName/routeName lub domena/nazwa aplikacji/podfolder/nazwa trasy - person Sagiv b.g; 19.03.2017
comment
Cześć, próbuję rozwiązania haszującego, jednak bez powodzenia. Pojawia się błąd createMemoryHistory is not a function. Możesz spojrzeć? stackoverflow.com/questions/45002573/ - person Leon Gaban; 10.07.2017
comment
@LeonGaban Wygląda na to, że od czasu napisania tej odpowiedzi React Router zmienił ich implementację. Mają teraz różne instancje routera dla różnych historii i konfigurują historię w tle. Podstawowe zasady są nadal takie same. - person Stijn de Witt; 17.07.2017
comment
@ YarinDekel Dzięki! I tak, może masz rację co do create-react-app, ponieważ CRA nie obsługuje SSR po wyjęciu z pudełka :( - person Stijn de Witt; 08.01.2019
comment
@Stijndewitt Natknąłem się na rozwiązanie, takie jak wspomniany przez Ciebie catch-all, który może wyeliminować wady SEO. Jednak dotyczy to tylko kocura. Może warto zaktualizować swoją odpowiedź, aby ją uwzględnić? - person ns533; 07.07.2019
comment
@ ns533 Czy możesz wyjaśnić, w jaki sposób wyeliminowałoby to wady SEO? AFAICT, to jest jak przepisywanie reguł w Apache... Oznacza to, że nadal kończy się to wysyłaniem prawie pustej strony, na której roboty nie będą w stanie znaleźć żadnej treści. - person Stijn de Witt; 08.07.2019
comment
@StijndeWitt Jeśli robot sieciowy nie renderuje strony z włączoną obsługą JavaScript, myślę, że tak się nie stanie. przeczytałem, że roboty indeksujące Google widzą jednak całą stronę. Łącząc te informacje z regułą, która przekierowuje www.mysite.com/blogpost/* do mojego index.html (nie google mądrzejszy), robot indeksujący Google nie powinien widzieć każdego posta na blogu jako unikalnej strony? - person ns533; 21.07.2019
comment
@ ns533 Tak, myślę, że Google będzie w stanie go zindeksować, ponieważ wydaje się, że rzeczywiście uruchamiają javascript. Nie wiem jednak, co m.in. Bing i Yahoo robią... - person Stijn de Witt; 31.07.2019
comment
@StijndeWitt Bardzo pomocny post, czy jest jakiś zasób wyjaśniający to podejście „Złap wszystko” zaimplementowane w .net? Właśnie doszedłem do wniosku, że szablon .Net Core React Web App stworzony przez Visual Studio ma właśnie ten problem. Próba trafienia do backendu za pomocą adresu URL działa po raz pierwszy. Za drugim razem już nigdy nie trafia do backendu. Nie mogę znaleźć sposobu na rozwiązanie tego. - person Arthur Medeiros; 08.11.2019
comment
@StijndeWitt Naprawdę dobre, wyczerpujące wyjaśnienie. Myślę, że rozwiązanie typu catch-all nie jest wielkim problemem i jest łatwe do skonfigurowania dla back-endów, takich jak Django - person Mohammed Shareef C; 14.12.2019
comment
@ ns533 Nie sądzę, że to rozwiązanie ogranicza się do Tomcata. Nginx z łatwością sobie z tym poradzi. W każdym razie jest to to samo rozwiązanie typu catch-all, ale obsługiwane przez sam serwer WWW (lub serwer odwrotnego proxy) - person Mohammed Shareef C; 14.12.2019
comment
Świetna odpowiedź! Niedawno opublikowałem artykuł, który zawiera wizualizacje tego, co dzieje się podczas routingu. Mam nadzieję, że to pomoże valerii-udodov.com/2020 /01/24/ Pozdrawiam - person Val; 29.01.2020
comment
Jedną z rzeczy, na które nie wskazano, było to, że jeśli załadujesz aplikację, a następnie ręcznie zmienisz adres URL w przeglądarce na adres URL obsługiwany przez router, cała aplikacja zostanie odświeżona. Miałem wrażenie, że przeglądarka przekieruje to do aplikacji, ale tak nie jest. Przeglądarka nie wie nic o React i po prostu robi to, co zawsze, czyli ładuje zawartość adresu URL z zaplecza. - person AndroidDev; 10.04.2020
comment
Tak, sposobem na manipulowanie adresem URL bez powodowania pobierania nowej strony z serwera jest użycie Historia API. Możesz otworzyć konsolę deweloperską i uruchomić tam linię JS, jeśli chcesz przetestować nawigację po stronie klienta. - person Stijn de Witt; 12.04.2020
comment
@StijndeWitt Właśnie zagłosowałem na tę dobrze napisaną odpowiedź. :) Tylko jedna rzecz: w podejściu Catch-all, co to znaczy bez konieczności unieważniania wszystkich ulubionych przez użytkownika.? - person Glenn Mohammad; 12.04.2020
comment
@GlennMohammad Wyobraź sobie, że zaczynasz od podejścia Hash History, a użytkownicy dodają ulubione (zakładki) do https://example.com/#/about, jeśli później przejdziesz na stronę serwera, renderowanie ich zakładek nie będzie już działać. Jeśli zaczniesz od Catch All i zrobisz https://example.com/about return index.html, możesz później zaimplementować renderowanie po stronie serwera, a zakładki użytkownika będą nadal działać. - person Stijn de Witt; 13.04.2020
comment
Znalazłem zabawny problem z HashRouter: pierwszy raz, gdy wpisuję adres URL, działa dobrze, ale jeśli ponownie wpiszę to samo, całkowicie przeładuje aplikację. Na przykład będąc w locahost:3000/ wpisuję locahost:3000/test, który nie istnieje, a następnie HashRouter nie przeładowuje strony. Ale jeśli spróbujesz ponownie wysłać to samo żądanie locahost:3000/test, aplikacja zostanie ponownie załadowana... Zastanawiam się, dlaczego... ???? - person Watchmaker; 20.04.2020
comment
odpowiedź na to pytanie jest bardzo dobrze wyjaśniona, ale moim rozwiązaniem było dodanie importu * jako serviceWorker z ./serviceWorker; i serviceWorker.register() w App.js i mogę odświeżyć strony bez brzydkich odniesień do adresów URL: medium.com/@krishnarai1985/ - person EduardoUstarez; 17.09.2020
comment
@EduardoUstarez Twoje rozwiązanie nie działa w ogólnym przypadku. Po prostu wyślij e-mailem link do znajomego, aby to przetestować. Pracownicy usług to sprawa po stronie klienta. Działają tylko na klientach, którzy już załadowali stronę w przeszłości i mają zainstalowany Service Worker. Potrzebujesz rozwiązania po stronie serwera, jeśli chcesz, aby adresy URL działały we wszystkich przypadkach. - person Stijn de Witt; 28.12.2020
comment
czy zwykłe przekierowanie odpowiedzi 404 i 403 do /index.html nie rozwiąże problemu? - person tymik; 30.12.2020
comment
@tymik uznałbym to za brudny hack. Chcę, aby moja witryna zwracała 404 dla adresów URL, które nie istnieją. Dzięki takiemu rozwiązaniu wszystkie adresy URL będą przekierowywać do index.html, ale nie jest to to, co chcę, aby moja witryna robiła. Może to jednak być dla Ciebie akceptowalne. - person Stijn de Witt; 03.01.2021
comment
Jak zacząć od podejścia typu „catch-all”? - person Yash Karanke; 04.01.2021
comment
@StijndeWitt, ale możesz obsłużyć 404 w swoim routerze i zwrócić wszystko, co chcesz w swojej aplikacji - wydaje się to całkiem dobre rozwiązanie dla aplikacji jednostronicowych. Działa całkiem dobrze z CloudFront w ten sposób. - person tymik; 04.01.2021
comment
@YashKaranke Jaki jest twój serwer? Musisz go skonfigurować tak, aby zwracał index.html dla wszystkich adresów URL, z których będzie korzystać Twoja aplikacja. Ale upewnij się, że robi to tylko dla HTML, a nie dla obrazów, skryptów itp. - person Stijn de Witt; 06.01.2021
comment
@StijndeWitt Apache, dodałem plik .htaccess w folderze publicznym i teraz działa idealnie - person Yash Karanke; 06.01.2021
comment
Mam na to rozwiązanie, ostatnio borykałem się z tym problemem w projekcie, prawdopodobnie napiszę odpowiedź później, gdy będę miał czas - person Inzamam Malik; 10.07.2021
comment
nie ma potrzeby używania HashRouter - person Inzamam Malik; 10.07.2021

Wszystkie odpowiedzi tutaj są niezwykle pomocne, dla mnie zadziałało skonfigurowanie mojego serwera Webpack tak, aby oczekiwał tras.

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

HistoryApiFallback naprawił ten problem. Teraz routing działa poprawnie i mogę odświeżyć stronę lub bezpośrednio wpisać adres URL. Nie musisz się martwić o obejścia na serwerze węzła. Ta odpowiedź oczywiście działa tylko wtedy, gdy używasz webpacka.

EDYCJA: zobacz moją odpowiedź tutaj, aby uzyskać bardziej szczegółowy powód, dla którego jest to konieczne: https://stackoverflow.com/a/37622953/5217568

person jmancherje    schedule 26.05.2016
comment
Pamiętaj, że zespół Webpack odradza używanie serwera deweloperskiego w środowisku produkcyjnym. - person Stijn de Witt; 13.06.2016
comment
Dla ogólnych celów programistycznych jest to najlepsze rozwiązanie. historyApiFallback wystarczy. Jak dla wszystkich innych opcji, można go również ustawić z CLI z flagą --history-api-fallback. - person Marco Lazzeri; 27.10.2016
comment
@Kunok Nie. Jest to szybka poprawka dla rozwoju, ale nadal będziesz musiał wymyślić coś dla produkcji. - person Stijn de Witt; 31.05.2017
comment
contentBase :':/', ponieważ do plików aplikacji można uzyskać dostęp z adresu URL - person Nezih; 21.02.2018
comment
Miałem ten problem na serwerze a także lokalnie. To naprawione dla lokalnych. Naprawiono .htaccess na serwerze. - person Izabela Furdzik; 05.06.2021
comment
Działa w React 17. Dzięki - person prathameshk73; 26.06.2021

Możesz zmienić plik .htaccess i wstawić go:

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

Używam react: "^16.12.0" i react-router: "^5.1.2" Ta metoda to Catch-all i jest prawdopodobnie najłatwiejszym sposobem na rozpoczęcie pracy.

person BrahimS    schedule 14.11.2016
comment
To działa dobrze! i najłatwiej, jeśli nie chcesz restrukturyzować swojej aplikacji - person mhyassin; 13.02.2018
comment
Nie zapomnij RewriteEngine On jako pierwszej linii - person Kai Qing; 01.11.2018
comment
Zauważ, że ta odpowiedź odnosi się do konfiguracji na serwerze Apache. To nie jest część aplikacji React. - person Colton Hicks; 17.07.2019
comment
Nie zrozumiałem powyższych odpowiedzi. Żaden z samouczków nie powiedział, że moje linki w ogóle nie będą działać na żywo. Jednak ten prosty plik htaccess zadziałał. Dziękuję - person Thomas Williams; 26.03.2020
comment
Działa to również w przypadku statycznego eksportu next.js. Ponieważ tomcat nie jest podobny do węzła, potrzebujemy tej dodatkowej konfiguracji do statycznego eksportu next.js. - person giri-jeedigunta; 04.04.2020
comment
To działa pięknie, co prawdopodobnie nie jest przypadkiem. 80% moich głębokich adresów URL można teraz odświeżyć, co stanowi zdecydowaną poprawę. - person Chris G; 29.05.2020
comment
Czy ktoś może mi pomóc? Gdzie jest umieszczony ten htaccess? Czy po dodaniu pliku trzeba uruchomić kompilację npm? - person Muteshi; 05.09.2020
comment
npm run build, a następnie dodałem to w .htacess w folderze kompilacji i przesłałem na cPanel, nadal nie działa - person Tayyab Ferozi; 10.12.2020
comment
@TayyabFerozi Musisz upewnić się, że ścieżka po RewriteBase i po ostatnim RewriteRule pasuje do folderu, w którym znajduje się aplikacja (jeśli jest to podfolder) - person Jason Ellis; 22.12.2020
comment
Miałem ten problem na serwerze a także lokalnie. To zostało naprawione dla serwera. Konfiguracja devServer naprawiła to lokalnie. - person Izabela Furdzik; 05.06.2021

Dla użytkowników React Router V4:

Jeśli spróbujesz rozwiązać ten problem za pomocą techniki Hash History, o której mowa w innych odpowiedziach, zauważ, że

<Router history={hashHistory} >

nie działa w V4, użyj zamiast tego HashRouter:

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

<HashRouter>
  <App/>
</HashRouter>

Odniesienie: HashRouter

person user2875289    schedule 18.04.2017
comment
Czy możesz podać szczegóły, dlaczego HashRouter naprawia ten problem? Podany przez Ciebie link nie wyjaśnia mi tego. Czy istnieje również sposób na ukrycie skrótu na ścieżce? Używałem BrowserRoutera, ale natknąłem się na ten problem 404.. - person Ian Smith; 07.06.2020
comment
używałem routera przeglądarki i powodował błąd 404 podczas odświeżania, ale potem wymieniłem router przeglądarki na router z haszem i nie działa dobrze. Dziękuję - person newbie; 31.07.2020

Użyłem create-react-app do stworzenia strony internetowej i ten sam problem został przedstawiony tutaj. Używam BrowserRouting z pakietu react-router-dom. Pracuję na serwerze Nginx i to, co mi to rozwiązało, to dodanie następujących elementów do /etc/nginx/yourconfig.conf

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

Co odpowiada dodaniu następujących elementów do .htaccess w przypadku korzystania z Appache

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

Wydaje się, że jest to również rozwiązanie sugerowane przez sam Facebook i można je znaleźć tutaj

person Aidin    schedule 04.09.2017
comment
Wow, takie proste rozwiązanie dla nginx; działa jak urok, jako nowy użytkownik nginx. Po prostu skopiuj i wklej i gotowe. +1 za link do oficjalnej dokumentacji fb. Tak trzymać. - person user3773048; 13.01.2019
comment
Dla przypomnienia: używam instancji AWS z nginx i aplikacją Angular. To działa. - person Diego Sarmiento; 03.06.2019
comment
ratujesz mnie. próbowałem naprawić mój problem z wczoraj, zmęczyłem kilka rozwiązań, ale nie udało mi się. w końcu pomogłeś mi rozwiązać ten problem z routerem. ach wielkie dzięki bracie - person Sharifur Robin; 22.09.2019
comment
Czy jest coś innego potrzebnego do reakcji: ^16.8.6, router reakcji: ^5.0.1? Wypróbowałem te rozwiązania (zarówno nginx, jak i apache) i nie działają. - person Mark A. Tagliaferro; 21.10.2019
comment
Ponieważ Facebook nie zmienił swojej dokumentacji w tym zakresie, mogę jedynie założyć, że procedura jest taka sama. Jednak nie próbowałem tego od jakiegoś czasu. - person Aidin; 21.10.2019
comment
Zajmuję się tym tygodniami i jest to jedyne rozwiązanie, które działa. Dziękuję - person abby; 29.05.2020
comment
Cześć, czy możesz mi powiedzieć, jak to będzie działać, jeśli folder React nie jest aliasem root? - person krishna lodha; 25.05.2021

W pliku index.html head dodaj następujące informacje:

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

Następnie podczas uruchamiania z serwerem webpack dev użyj tego polecenia.

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

--history-api-fallback to ważna część

person Efe Ariaroo    schedule 01.04.2018
comment
To działało świetnie! Jakieś linki, aby dowiedzieć się więcej o tym, jak otrzymałeś/znalazłeś to rozwiązanie? - person justDan; 26.06.2018
comment
Przepraszam bracie. Znalazłem to dzięki wypróbowanej i prawdziwej technice prób i błędów. - person Efe Ariaroo; 30.06.2018
comment
Warto wspomnieć, że jeśli używasz podstawowego atrybutu href, który nie jest /, to HashRouter nie będzie działać (jeśli używasz routingu mieszającego) - person scrowler; 17.01.2019
comment
Znacznik ‹base href=/› zrobił to za mnie. Dzięki za to. Serwer deweloperski Webpack ciągle próbował pobrać pakiet ze ścieżki/‹pakietu› i kończył się niepowodzeniem. - person Malisbad; 26.03.2019
comment
Używam trybu React.js + Webpack. Dodałem parametr --history-api-fallback w pliku package.json. Wtedy odświeżanie strony działa poprawnie. Za każdym razem, gdy zmieniam kod, strona internetowa odświeża się automatycznie. ``` skrypty: { start: rimraf build && cross-env NODE_ENV='development' webpack --mode development && cross-env NODE_ENV=development webpack-dev-server --history-api-fallback, ... } `` ` - person NinjaDev; 13.08.2020

Router można wywołać na dwa różne sposoby, w zależności od tego, czy nawigacja odbywa się na kliencie, czy na serwerze. Masz go skonfigurowany do działania po stronie klienta. Kluczowym parametrem jest drugi po metodzie uruchamiania, czyli lokalizacji .

Gdy używasz składnika React Router Link, blokuje on nawigację w przeglądarce i wywołuje funkcję transitionTo w celu wykonania nawigacji po stronie klienta. Używasz HistoryLocation, więc używa interfejsu API historii HTML5, aby dopełnić iluzję nawigacji, symulując nowy adres URL na pasku adresu. Jeśli używasz starszych przeglądarek, to nie zadziała. Będziesz musiał użyć komponentu HashLocation.

Po naciśnięciu przycisku odświeżania omijasz cały kod React i React Router. Serwer otrzymuje żądanie dla /joblist i musi coś zwrócić. Na serwerze należy przekazać żądaną ścieżkę do metody run, aby wyrenderować poprawny widok. Możesz użyć tej samej mapy trasy, ale prawdopodobnie będziesz potrzebować innego połączenia z Router.run. Jak zauważa Charles, możesz użyć przepisywania adresów URL, aby sobie z tym poradzić. Inną opcją jest użycie serwera node.js do obsługi wszystkich żądań i przekazanie wartości ścieżki jako argumentu lokalizacji.

Na przykład ekspresowo może to wyglądać tak:

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

Zauważ, że ścieżka żądania jest przekazywana do run. Aby to zrobić, potrzebujesz silnika widoku po stronie serwera, do którego możesz przekazać wyrenderowany kod HTML. Istnieje kilka innych kwestii związanych z używaniem renderToString i uruchamianiem Reacta na serwerze. Po wyrenderowaniu strony na serwerze, gdy aplikacja zostanie załadowana do klienta, zostanie ona ponownie wyrenderowana, aktualizując w razie potrzeby renderowany kod HTML po stronie serwera.

person Todd    schedule 21.01.2015
comment
przepraszam Przepraszam, czy możesz wyjaśnić pls następną instrukcję, gdy naciśniesz odświeżanie, omijasz cały kod React i React Router? Dlaczego tak się dzieje? - person VB_; 08.09.2015
comment
Router React jest zwykle używany do obsługi różnych „ścieżek” tylko w przeglądarce. Można to zrobić na dwa typowe sposoby: ścieżka skrótu w starszym stylu i nowszy interfejs API historii. Odświeżenie przeglądarki spowoduje żądanie serwera, które ominie kod routera React po stronie klienta. Będziesz musiał obsłużyć ścieżkę na serwerze (ale tylko wtedy, gdy używasz interfejsu API historii). Możesz do tego użyć routera React, ale musisz zrobić coś podobnego do tego, co opisałem powyżej. - person Todd; 09.09.2015
comment
Rozumiem. Ale jak być, jeśli serwer jest w języku innym niż JS (powiedzmy Java)? - person VB_; 09.09.2015
comment
W takim przypadku sprawy stają się trudniejsze. Obietnicę aplikacji izomorficznych najlepiej zrealizować za pomocą JS na kliencie i serwerze. Jeśli nie możesz uruchomić JS w swoim frameworku Java, tak naprawdę nie będziesz miał izomorfizmu ani nie będziesz w stanie użyć routera React. Istnieje kilka rozwiązań po stronie serwera, takich jak ReactJS.NET, które mogą to zrobić. Łatwiej jest jednak używać Node.js. - person Todd; 11.09.2015
comment
jakie są pierwsze parametry tras w tej odpowiedzi? Ponieważ kiedy dołączysz coś takiego ‹Nazwa trasy=root path=/ handler={App} /› otrzymasz błąd SyntaxError: Nieoczekiwany token ‹ - person Code Uniquely; 15.10.2015
comment
przepraszam… masz na myśli, że potrzebujesz ekspresowego serwera do renderowania trasy, która nie jest rootem? Po raz pierwszy byłem zdumiony, że definicja izomorfizmu nie uwzględniała pobierania danych w swojej koncepcji (sprawy są desperacko skomplikowane, jeśli chcesz renderować widok Z danymi po stronie serwera, chociaż byłaby to oczywista potrzeba SEO — i tak twierdzi izomorfizm). Teraz jestem jak WTF zareagował, poważnie… Popraw mnie, jeśli się mylę, czy ember/angular/backbone wymaga serwera do renderowania trasy? Naprawdę nie rozumiem tego nadętego wymogu korzystania z tras - person Ben; 17.10.2015
comment
@Ben Popraw mnie, jeśli się mylę, czy ember/angular/backbone wymaga serwera do renderowania trasy? Tak, w rzeczywistości robią to, gdy używasz lokalizacji historii („prawdziwe adresy URL”). Wszystkie frameworki JavaScript to robią. Pamiętaj, kiedy żądasz adresu URL, najpierw trafiasz na serwer. Dzieje się tak, że OP nie kieruje poprawnie po stronie serwera. Powinien albo po prostu użyć lokalizacji skrótu, albo skonfigurować serwer tak, aby zawsze obsługiwał HTML na wszystkich możliwych trasach. - person Stijn de Witt; 17.11.2015
comment
Czy to oznacza, że ​​odświeżanie w routerze reakcji nie działa, jeśli moja aplikacja nie jest izomorficzna? - person Matt; 07.12.2015
comment
Aby odświeżenie zadziałało, musisz wywołać router z kodu klienta (domyślne środowisko React) oraz z kodu serwera (Node.js). Jeśli możesz to zrobić, Twoja aplikacja jest izomorficzna. Zauważ, że kod w tej odpowiedzi nie odzwierciedla zmian w nowej wersji React Router 1.0 (jak na razie). - person Todd; 08.12.2015
comment
@Matt Jeśli twoja aplikacja React nie jest izomorficzna (a może nawet nie używasz JS po stronie serwera, ale powiedzmy PHP), najlepiej jest mieć skrypt po stronie serwera, który zwraca tę samą stronę dla wszystkich możliwych tras. Do klienta zostanie wysłany tylko ogólny kod HTML kodu początkowego. Po uruchomieniu React-Router sprawdza adres URL i wszystko działa zgodnie z oczekiwaniami. Ale minusem jest SEO. Google zobaczy tylko ten kod początkowy i nie będzie indeksować Twojej witryny. - person Stijn de Witt; 14.04.2016

Jeśli używasz aplikacji Create React:

Jest świetny spacer po tym problemie z rozwiązaniami dla wielu głównych platform hostingowych, które można znaleźć TUTAJ na stronie Utwórz aplikację React. Na przykład używam React Router v4 i Netlify do mojego kodu frontendowego. Wystarczyło dodać 1 plik do mojego folderu publicznego („_redirects”) i jedną linię kodu w tym pliku:

/*  /index.html  200

Teraz moja strona poprawnie renderuje ścieżki takie jak mysite.com/pricing po wejściu do przeglądarki lub gdy ktoś kliknie odświeżanie.

person Colton Hicks    schedule 09.06.2017
comment
jeśli używasz serwera HTTP Apache, to .htaccess nie działa, sprawdź wersję Apache, ponieważ w wersja 2.3.9 i nowsze domyślne AllowOverride< /b> oznacza Brak, próbując zmienić AllowOverride na Wszystko. sprawdź tę odpowiedź - person Muhammad Adam C; 13.04.2021

Jeśli hostujesz aplikację React za pośrednictwem AWS Static S3 Hosting i CloudFront

Ten problem pojawił się, gdy CloudFront odpowiedział komunikatem 403 Access Denied, ponieważ oczekiwał, że /some/other/path będzie istnieć w moim folderze S3, ale ta ścieżka istnieje tylko wewnętrznie w routingu Reacta za pomocą routera React.

Rozwiązaniem było ustawienie reguły dystrybucji stron błędów. Przejdź do ustawień CloudFront i wybierz swoją dystrybucję. Następnie przejdź do zakładki „Strony błędów”. Kliknij „Utwórz niestandardową odpowiedź na błąd” i dodaj wpis dla 403, ponieważ jest to kod stanu błędu, który otrzymujemy. Ustaw Ścieżkę strony odpowiedzi na /index.html, a kod statusu na 200. Efekt końcowy zaskakuje mnie prostotą. Strona indeksu jest obsługiwana, ale adres URL jest zachowywany w przeglądarce, więc po załadowaniu aplikacji React wykryje ścieżkę adresu URL i nawiguje do żądanej trasy.

Reguła stron błędów 403

person th3morg    schedule 23.11.2017
comment
To jest dokładnie to, czego potrzebowałem. Dziękuję Ci. - person Jonathan; 19.09.2019
comment
Więc... wszystkie twoje adresy URL działają, ale zwracasz kod statusu 403? To jest niepoprawne. Oczekiwane kody stanu powinny należeć do zakresu 2xx. - person Stijn de Witt; 21.10.2019
comment
@StijndeWitt Nie jestem pewien, czy dobrze rozumiesz. CloudFront obsłuży wszystko - klient nie zobaczy żadnych kodów statusu 403. Zmiana routingu odbywa się po stronie serwera, renderuje stronę indeksu, utrzymuje adres URL i w rezultacie zapewnia poprawną trasę. - person th3morg; 22.10.2019
comment
@th3morg Ach tak, teraz rozumiem. Brakowało mi, że pozwala to również na wypełnienie kodu statusu odpowiedzi jako 200. Więc w zasadzie mapujesz status 403 na status 200... Wygląda dobrze... z wyjątkiem tego, że może jeśli otrzymasz 403 jako wynik z jakiegoś innego powodu z tego powodu nie będziesz mógł tego zobaczyć. - person Stijn de Witt; 23.10.2019
comment
@StijndeWitt Jest to konkretnie 403 z CloudFront, więc jeśli powiedziałbyś, że wykonasz wywołanie API, które spowodowało asynchroniczną odpowiedź 403 z Twojej witryny, to zachowywałoby się normalnie. Nie wyobrażam sobie scenariusza, w którym chciałbyś ujawnić zachowanie 403 z samego CloudFront, chociaż być może jest takie. To rozwiązanie powinno jednak działać w ponad 99% przypadków użycia. - person th3morg; 23.10.2019
comment
dzięki za to @th3morg. Czy ta konfiguracja działa również w przypadku ścieżek wielopoziomowych? Dla mnie działa świetnie, jeśli jakakolwiek ścieżka na poziomie głównym, taka jak domena/rejestracja, domena/logowanie, domena/‹identyfikator dokumentu›, ale nie działa w przypadku ścieżek wielopoziomowych, takich jak domena/dokument/‹identyfikator dokumentu›. - person Pargles; 03.02.2020
comment
Och, piękna istoto! Musiałem ustawić go na odpowiedź 404 i zadziałało jak urok! - person Nnanyielugo; 06.07.2020

To może rozwiązać twój problem

Z tym samym problemem spotkałem się również w aplikacji ReactJS w trybie produkcyjnym. Oto 2 rozwiązanie problemu.

1. Zmień historię routingu na hashHistory zamiast browserHistory w miejscu

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

Teraz zbuduj aplikację za pomocą polecenia

sudo npm run build

Następnie umieść folder kompilacji w folderze var/www/. Teraz aplikacja działa dobrze z dodaniem tagu # w każdym adresie URL. tak jak

localhost/#/home localhost/#/aboutus

Rozwiązanie 2: Bez tagu # przy użyciu browserHistory,

Ustaw swoją historię = {browserHistory} w routerze, teraz zbuduj ją za pomocą sudo npm run build.

Musisz utworzyć plik conf, aby rozwiązać nie znaleziono strony 404, plik conf powinien wyglądać tak.

otwórz terminal wpisz poniższe polecenia

cd /etc/apache2/sites-available ls nano sample.conf Dodaj do niego poniższą zawartość.

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

Teraz musisz włączyć plik sample.conf za pomocą następującego polecenia

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

następnie poprosi Cię o ponowne załadowanie serwera Apache za pomocą usługi sudo apache2 reload lub restart

następnie otwórz folder localhost/build i dodaj plik .htaccess o treści poniżej.

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

Teraz aplikacja działa normalnie.

Uwaga: zmień 0.0.0.0 IP na lokalny adres IP.

Jeśli masz jakiekolwiek wątpliwości co do tego, możesz zgłosić komentarz.

Mam nadzieję, że pomoże innym.

person Venkatesh Somu    schedule 07.02.2017
comment
Czy pierwsze rozwiązanie będzie działać dla "react-router-dom": "^5.1.2" ?, używam <BrowserRouter> - person 151291; 13.12.2019
comment
.htaccess naprawił to dla mnie. - person beltrone; 03.02.2021
comment
gdzie otrzymam historię przeglądarki w rozwiązaniu 2. - person Sushil; 06.02.2021
comment
dodawanie tylko pliku .htaccess w folderze build zostało dla mnie naprawione, dzięki człowieku - person coderLogs; 19.05.2021

Jeśli hostujesz swoją aplikację React w IIS, po prostu dodaj plik web.config zawierający:

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

Dzięki temu serwer IIS ma zwrócić stronę główną do klienta zamiast błędu 404 i nie ma potrzeby używania historii skrótów.

person Chtiwi Malek    schedule 18.10.2017

Webpack Dev Server ma opcję, aby to włączyć. Otwórz package.json i dodaj --history-api-fallback. To rozwiązanie zadziałało dla mnie.

react-router- samouczek

person sree    schedule 09.09.2016
comment
Jest w porządku z webpack-dev-server, ale jak to naprawić w kompilacji produkcyjnej? - person Hussain; 15.08.2018

@WhozCraig, chciałbym dać +1 Twojej odpowiedzi. Komentarze nie dają reputacji. Niesprawiedliwy.
person Isaac Pak    schedule 09.08.2017
comment
uzyskiwanie ścieżki niezdefiniowanej - person Goutham; 10.08.2017
comment
@Goutham Na górze pliku server.js dodaj import path from 'path lub const path = require('path') - person Isaac Pak; 10.08.2017
comment
krok 2 (złap wszystko za pomocą /*) właśnie uratował mi dzień. Dziękuję Ci! :) - person Atlas7; 22.11.2017
comment
To działa, dla osób korzystających z redux i zainteresowanych podłączonym routerem, zobacz ten przykład: github.com/supasate/connected-react-router/tree/master/examples/ - person cjjenkinson; 16.04.2018

Dodaj to do webpack.config.js:

devServer: {
    historyApiFallback: true
}
person suraj    schedule 11.09.2017
comment
To jest świetne dla programistów, ale nie pomaga w kompilacjach produkcyjnych. - person KFunk; 05.05.2020

Spróbuj dodać plik „.htaccess” w folderze publicznym za pomocą poniższego kodu.

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
Dzięki, to właśnie działało dla mnie w Fedorze 28 z apache. Żadna z powyższych zasad przepisywania ani tych na stronie CRA nie działała dla mnie. Dodałem je do konfiguracji hosta wirtualnego zamiast w osobnym pliku .htaccess. - person boerre; 25.11.2019

Jeśli masz kopię zapasową swojego index.html, upewnij się, że w pliku index.html masz to:

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

Może się to różnić w zależności od projektu.

person Matt Goo    schedule 03.05.2016
comment
Dodaj to do swojego html head: ‹base href=/› - person Efe Ariaroo; 02.04.2018

Jeśli korzystasz z Firebase, wszystko, co musisz zrobić, to upewnić się, że masz właściwość rewrites w pliku firebase.json w katalogu głównym aplikacji (w sekcji hostingu).

Na przykład:

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

Mam nadzieję, że oszczędzi to komuś innemu skarbu frustracji i straconego czasu.

Udanego kodowania...

Dalsza lektura na ten temat:

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

Firebase CLI: konfiguracja jako aplikacja jednostronicowa (przepisz wszystkie adresy URL do /index.html)

person Joshua Dyck    schedule 24.07.2018
comment
Jesteś legendą - person Perniferous; 29.03.2019

Dla tych, którzy korzystają z IIS 10, należy to zrobić, aby to naprawić. Upewnij się, że używasz z tym browserHistory. Jako odniesienie podam kod do routingu, ale nie to ma znaczenie, liczy się kolejny krok po kodzie komponentu poniżej:

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

Ponieważ problem polega na tym, że IIS otrzymuje żądanie z przeglądarek klienckich, zinterpretuje adres URL tak, jakby prosi o stronę, a następnie zwróci stronę 404, ponieważ nie ma dostępnej strony. Wykonaj następujące czynności:

  1. Otwórz IIS
  2. Rozwiń Serwer, a następnie otwórz folder Witryny
  3. Kliknij stronę/aplikację
  4. Przejdź do stron błędów
  5. Otwórz pozycję statusu błędu 404 na liście
  6. Zamiast opcji „Wstaw zawartość z pliku statycznego do odpowiedzi na błąd”, zmień ją na „Wykonaj adres URL w tej witrynie” i dodaj wartość ukośnika „/” do adresu URL.

I teraz będzie działać dobrze.

tu wpisz opis obrazu tu wpisz opis obrazu

Mam nadzieję, że to pomoże. :-)

person Martin Lloyd Jose    schedule 29.05.2018
comment
najlepsze rozwiązanie po 3-4 godzinach poszukiwań. wielkie dzięki :) - person KMR; 17.09.2020
comment
Niech cię Bóg błogosławi człowieku - person ArtemiZ Studio; 01.06.2021

Znalazłem rozwiązanie dla mojego SPA z routerem React (Apache). Po prostu dodaj .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>

źródło: https://gist.github.com/alexsasharegan/173878f9d67055bfef63449fa7136042

person Sasha Ignashevich    schedule 20.01.2019

Nie używam jeszcze renderowania po stronie serwera, ale napotkałem ten sam problem, co OP, w którym Link wydawał się działać dobrze przez większość czasu, ale nie powiodło się, gdy miałem parametr. Udokumentuję tutaj moje rozwiązanie, aby zobaczyć, czy komuś pomoże.

Mój główny jsx zawiera to:

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

Działa to dobrze w przypadku pierwszego pasującego łącza, ale gdy :id zmienia się w wyrażeniach <Link> zagnieżdżonych na stronie szczegółów tego modelu, zmienia się adres URL na pasku przeglądarki, ale zawartość strony nie zmieniła się początkowo w celu odzwierciedlenia połączonego modelu.

Kłopot polegał na tym, że użyłem props.params.id do ustawienia modelu w componentDidMount. Komponent jest montowany tylko raz, więc oznacza to, że pierwszy model jest tym, który przykleja się na stronie, a kolejne Linki zmieniają rekwizyty, ale pozostawiają stronę bez zmian.

Ustawienie modelu w stanie komponentu zarówno w componentDidMount, jak iw componentWillReceiveProps (gdzie jest oparty na następnych właściwościach) rozwiązuje problem, a zawartość strony zmienia się, aby odzwierciedlić pożądany model.

person Paul Whipp    schedule 12.09.2016
comment
Lepiej byłoby użyć konstruktora komponentu (który ma również dostęp do props) i.o. componentDidMount jeśli kiedykolwiek będziesz chciał spróbować renderowania po stronie serwera. Ponieważ componentDidMount jest wywoływane tylko w przeglądarce. Jego celem jest robienie rzeczy z DOM, takich jak dołączanie detektorów zdarzeń do body itd., których nie można zrobić w render. - person Stijn de Witt; 20.12.2016

Ten temat jest trochę stary i rozwiązany, ale chciałbym zaproponować proste, jasne i lepsze rozwiązanie. Działa, jeśli korzystasz z serwera WWW.

Każdy serwer WWW ma możliwość przekierowania użytkownika na stronę błędu w przypadku http 404. Aby rozwiązać ten problem należy przekierować użytkownika na stronę indeksu.

Jeśli używasz serwera bazowego Java (tomcat lub dowolny serwer aplikacji Java), rozwiązanie może być następujące:

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>

Przykład:

  • POBIERZ http://example.com/about
  • Serwer WWW zgłasza http 404, ponieważ ta strona nie istnieje po stronie serwera
  • konfiguracja strony błędu informuje serwer, że odsyła stronę index.jsp z powrotem do użytkownika
  • wtedy JS wykona resztę pracy po stronie klienta, ponieważ adres URL po stronie klienta to nadal http://example.com/about.

To wszystko, koniec z magicznymi potrzebami:)

person zappee    schedule 15.01.2017
comment
To było niesamowite! Używam serwera Wildfly 10.1 i dokonałem tej aktualizacji w moim pliku web.xml, z wyjątkiem tego, że ustawiono lokalizację na „/”. Stało się tak, ponieważ w moim kodzie React użyłem historii przeglądarki w następujący sposób: const browserHistory = useRouterHistory(createHistory)({ basename: '/<appname>' }); - person Chuck L; 02.06.2017
comment
Czy na pewno nie ma to wpływu na SEO? Stronom, które faktycznie istnieją, nadajesz status 404. Użytkownik może nigdy nie zdawać sobie z tego sprawy, ale boty poświęcają dużo uwagi, w rzeczywistości tak bardzo, że nie będą skrobać Twojej strony. - person subharb; 15.12.2017

Jeśli używasz Express lub innego frameworka w backend , możesz dodać podobną konfigurację jak poniżej i sprawdzić publiczną ścieżkę Webpack w konfiguracji, powinna działać dobrze nawet po ponownym załadowaniu, jeśli używasz BrowserRouter

expressApp.get('/*', (request, response) => {
    response.sendFile(path.join(__dirname, '../public/index.html'));
});
person neeraj-dixit27    schedule 09.03.2018
comment
to najprostsze rozwiązanie. pamiętaj, że ta trasa powinna przebiegać za innymi trasami, ponieważ jest to łatwe do opanowania - person dcsan; 14.02.2020

Naprawienie błędu „nie można uzyskać /URL” podczas odświeżania lub bezpośredniego wywoływania adresu URL.

Skonfiguruj swój webpack.config.js, aby oczekiwał podanego linku na takie trasy.

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

możesz spróbować przeczytać to wszystko, chociaż nie jest moje:

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

Naprawianie routingu aplikacji Oto jak w końcu naprawić routing. Aby Apache przekierowywał żądania do index.html, gdzie znajduje się nasza aplikacja, musimy zmodyfikować plik .htaccess. Jeśli nie ma jeszcze takiego pliku w folderze Twojej aplikacji, po prostu go utwórz.

Następnie upewnij się, że umieściłeś te 4 wiersze, które w magiczny sposób sprawią, że Twój routing będzie działał.

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

Po umieszczeniu tego pliku .htaccess w tym samym katalogu co index.html, Apache przekieruje każde nowe żądanie bezpośrednio do Twojej aplikacji.

Bonus: Wdrażanie aplikacji React w podkatalogu

Jeśli wdrażasz swoją aplikację w podkatalogu, aby była dostępna m.in. przez https://myapp.com/the-app, wkrótce zauważysz, że jest inny kwestia. Każde kliknięcie nowej trasy spowoduje przekształcenie adresu URL w coś takiego jak https://myapp.com/route-abc – który po przeładowaniu ponownie się zepsuje. Ale jest na to prosta poprawka:

BrowserRouter ma właściwość nazwaną basename, w której możesz określić ścieżkę do podkatalogu:

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
Jest to bardzo prosta poprawka dla tych, którzy chcą uruchomić swoją CRA z innego katalogu. Używam react-router-dom, więc musiałem dołączyć basename do <BrowserRouter />. Ale ta prosta poprawka pozwoli Ci zaoszczędzić dużo czasu. Dziękuję za ten wkład! - person Josh Cronkhite; 17.09.2020
comment
Dziękuję. Twoje rozwiązanie oszczędza mój czas. :) - person Adnan Ahmad; 18.11.2020
comment
Cieszę się, że mogłem pomóc... :) - person Rishabh Jain; 09.12.2020

Używanie HashRouter działało dla mnie również z Redux, po prostu zamień:

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

Jeśli używasz polecenia create-react-app,

aby wygenerować aplikację React to pakiet.json musi mieć jedną zmianę, aby poprawnie uruchomić produkcyjną kompilację React SPA w przeglądarce. Otwórz package.json i dodaj do niego następujący segment kodu,

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

Tutaj najważniejszą częścią jest --history-api-fallback, aby umożliwić wywołanie zwrotne interfejsu API historii.

Czasami otrzymasz błąd 404, jeśli użyjesz Spring lub innego interfejsu API zaplecza. Tak więc w takiej sytuacji musisz mieć kontroler na zapleczu, aby przekazywać dowolne żądanie (które chcesz) do pliku index.html, aby obsłużyć go React-router. Poniżej zademonstrujemy przykładowy kontroler napisany za pomocą sprężyny.

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

na przykład, jeśli przyjmiemy back-endowy punkt końcowy API REST jako abc (http://localhost:8080/abc/**), każde żądanie przychodzące do tego punktu końcowego będzie przekierowywać do aplikacji React (plik index.html) i reagować- router zajmie się tym później.

person Malinda    schedule 30.01.2020
comment
Możesz także dodać wiele mapowań w ten sposób: @RequestMapping({/myurl1/**, /myurl2/**}) - person Craigo; 17.12.2020

W przypadku, gdy ktoś szuka rozwiązania w React JS SPA z Laravel. Przyjęta odpowiedź jest najlepszym wyjaśnieniem, dlaczego takie problemy się zdarzają. Jak już wyjaśniono, musisz skonfigurować zarówno stronę klienta, jak i stronę serwera. W szablonie ostrza dołącz dołączony plik js, pamiętaj, aby użyć URL facade w ten sposób

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

Upewnij się, że w swoich trasach dodaj to do głównego punktu końcowego, w którym znajduje się szablon ostrza. Na przykład,

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

Powyższe jest głównym punktem końcowym szablonu ostrza. Teraz dodaj również opcjonalną trasę,

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

Problem polega na tym, że najpierw ładowany jest szablon ostrza, a następnie router React. Tak więc, kiedy ładujesz '/setting-alerts', ładuje html i js. Ale kiedy ładujesz '/setting-alerts/about', najpierw ładuje się po stronie serwera. Ponieważ po stronie serwera nie ma nic w tej lokalizacji, zwraca nie znaleziono. Gdy masz ten opcjonalny router, ładuje on tę samą stronę i router React jest również ładowany, a następnie loader React decyduje, który komponent pokazać. Mam nadzieję że to pomoże.

person Koushik Das    schedule 14.11.2017
comment
Czy można załadować do jednego dokładnego URI na serwer, a następnie serwer przekieruje do Reacta? Na przykład, kiedy ładuję /user/{userID}, wystarczy zwrócić uniwersalny widok HTML /user, przynieść identyfikator i wywołać go za pomocą AJAX lub axios. czy jest to możliwe do zrobienia? czy są przyjazne dla SEO? - person Ryuujo; 22.02.2019
comment
Używam tego kodu dla moich SPA z backendem Laravel: Route::any('{any?}', 'MyController@index'); Pasuje do dowolnej trasy i przekazuje go do SPA - person Felix Geenen; 08.09.2020

Ponieważ używam .Net Core MVC, pomogło mi coś takiego:

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

Zasadniczo po stronie MVC wszystkie niedopasowane trasy zostaną przypisane do Home/Index, jak określono w startup.cs. Wewnątrz Index można uzyskać oryginalny adres URL żądania i przekazać go tam, gdzie jest to potrzebne.

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
Jeśli web API jest oddzielone od aplikacji, jak sobie z tym poradzisz? - person Dayán Ruiz; 01.05.2019
comment
@dayanrr91 jeśli twój projekt ma web api, i tak nie będziesz potrzebować routingu po stronie serwera. Uważam, że twój router reakcji powinien przeczytać adres URL i wykonać odpowiedni routing. Nic nie powinno go blokować - person Elnoor; 01.05.2019
comment
Twój komentarz jest bardzo mile widziany, ale mam pytanie, właśnie dodałem HashRouter, ale teraz, gdy wchodzę ręcznie pod dowolny adres URL, przekieruje on do mojego komponentu domowego zamiast do mojego domu, a następnie do komponentu, który próbowałem wsiadanie, czy jest jakieś obejście tego? - person Dayán Ruiz; 01.05.2019
comment
@dayanrr91 nie mam pojęcia, nigdy nie próbowałem hashroutera, ale myślę, że powinno to mieć coś wspólnego z twoim kodem. Sposób działania hashroutera powinien być podobny do routera przeglądarki. Również właśnie przetestowałem tutaj w tej piaskownicy, działa dobrze codesandbox.io/s/25okp1mny, przetestuj adres URL 25okp1mny.codesandbox.io/#/roster/5 - person Elnoor; 01.05.2019

Jeśli korzystasz z usług IIS; Dodanie tego do mojego webconfig rozwiązało mój problem

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

Możesz wykonać podobną konfigurację dla dowolnego innego serwera

person Barny    schedule 26.04.2017

Dla tych z was, którzy są tutaj, ponieważ próbujecie obsługiwać aplikację React z katalogu wirtualnego IIS (nie z katalogu głównego witryny), może to być dla was.

Podczas konfigurowania przekierowań '/' nie będzie działać samodzielnie, dla mnie również tam potrzebna jest nazwa katalogu wirtualnego. Oto jak wyglądała moja konfiguracja sieciowa:

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

Oprócz pliku web.config aplikacja React sama w sobie wymagała kilku zmian:

w package.json musisz dodać wpis 'homepage':

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

Dodałem nazwę bazową do obiektu historii przeglądarki, którą przekazuję do routera, aby uzyskać dostęp do historii:

import  {createBrowserHistory } from 'history';

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

Dodałem również tę właściwość na moim routerze React w App.js:

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

Wreszcie w index.html dodałem następującą zakładkę nad tagiem 'title'

  <base href="%PUBLIC_URL%/">

może być tak, że niektóre kroki wymagały notatki, ale wydaje się, że zrobiło to za mnie pracę. Nie wiem, jak skonfigurować go, aby działał w katalogu głównym witryny lub w katalogu wirtualnym bez rekompilacji, ponieważ strona główna w package.json nie może zostać zamieniona po kompilacji, o ile mi wiadomo.

person WraithNath    schedule 19.07.2020
comment
Ostatnie dwie linijki kodu w twoim poście uratowały mnie. Dziękuję! basename w <Router /> i <base /> w index.html. - person Craig Howell; 28.04.2021
comment
@CraigHowell - Cieszę się, że to pomogło! Wróciłem do tego postu, aby sobie przypomnieć! - person WraithNath; 30.04.2021

Naprawdę niesamowite odpowiedzi już !! Ale jeśli hostujesz przy użyciu nginx i potrzebujesz szybkiej naprawy ... dodaj następujący wiersz do swojej konfiguracji nginx w bloku lokalizacji

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

Dodaję więcej informacji do odpowiedzi Joshuy Dycka.

Jeśli korzystasz z Firebase i chcesz używać zarówno trasy głównej, jak i trasy podkatalogu, musisz dodać następujący kod w swoim firebase.json:

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

Przykład:

Budujesz stronę internetową dla klienta. Chcesz, aby właściciel witryny dodał informacje w https://twoja.domena.com/management podczas gdy użytkownicy witryny przejdą do https://twoja.domena.com.

W takim przypadku Twój plik firebase.json będzie wyglądał tak:

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

Używam WebPacka, miałem ten sam problem Rozwiązanie=> W twoim pliku 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();
  });

Dlaczego moja aplikacja nie renderuje się po odświeżeniu?

person Vishal Singh    schedule 19.02.2019
comment
Zrobiło to za mnie! Początkowo miałem res.sendFile(path.JOIN(publicPath, index.html)); Zmieniłem join na resolved jak w powyższym przykładzie na: res.sendFile(path.resolve(./dist, index.html)); Bawiłem się również z __dirname, ale tak naprawdę nie mogłem go zrozumieć ani uruchomić, więc ręcznie skopiowałem ./dist, ponieważ jest to miejsce, z którego jest obsługiwany mój index.html. Zadeklarowałem to również wcześniej: app.use(express.static(./dist)); - person logixplayer; 10.05.2020

Zastosowaliśmy ekspresowe podejście do obsługi 404

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

Działa jak marzenie. Demo na żywo to nasza strona

person Zameer Ansari    schedule 22.09.2019
comment
to zadziałało dla mnie, dziękuję za odpowiedź! - person Apostolos; 13.05.2021

Rozwiązałem ten problem zmieniając webpack.config.js.

moja nowa konfiguracja wygląda tak:

Przed:

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


devServer: {
  port: 3000
}

Po:

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

Jeśli używasz go na Google Bucket, prostym rozwiązaniem jest rozważenie „index.html” dla strony z błędem (404 nie znaleziono).

To do so:

  1. Na liście zasobników znajdź utworzony zasobnik.
  2. Kliknij menu przepełnienia zasobnika (...) powiązane z zasobnikiem i wybierz Edytuj konfigurację witryny.
  3. W oknie dialogowym konfiguracji witryny określ również stronę główną jako stronę błędu.
person Sansei    schedule 16.07.2020
comment
To nie działa dla mnie - person Md. Parvez Alam; 16.12.2020

Używając Express na backendzie i React na frontendzie (bez React-create-app) z zasięgiem/routerem, wyświetlany jest poprawny komponent reagowania zasięgu/routera, a link menu jest ustawiony na aktywny styl po naciśnięciu klawisza Enter w pasku adresu np. http://localhost:8050/pages. Proszę o kasę poniżej lub bezpośrednio do mojego repozytorium https://github.com/nickjohngray/staticbackeditor, wszystkie kod tam jest.

Pakiet internetowy:

Skonfiguruj serwer proxy. Pozwala to dowolnym wywołaniom z portu 3000 (React) na wywołanie serwera, w tym wywołanie pobrania index.html lub czegokolwiek w pasku adresu po naciśnięciu klawisza Enter. umożliwia również wywołania trasy API, aby uzyskać dane JSON

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

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

Ustaw trasy ekspresowe

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

});

To będzie pasować do każdego żądania z React, po prostu zwróci stronę index.html, która znajduje się w moim folderze dist, ta strona ma oczywiście bardziej jednostronicową aplikację React. (uwaga wszystkie inne trasy powinny pojawić się powyżej tego, w moim przypadku są to moje trasy API)

Reaguj Trasy

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

Trasy te są zdefiniowane w moim komponencie Układ, który wczytuje odpowiedni komponent, gdy ścieżka jest zgodna.

Konstruktor React Layout

 constructor(props) {
        super(props);


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

Konstruktor układu jest wywoływany zaraz po załadowaniu. Tutaj nazywam mój adres URL zmiany redux, którego moje menu nasłuchuje, dzięki czemu może podświetlić poprawną pozycję menu, jak poniżej:

Kod menu

<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

W moim przypadku adres URL nie ładował się, gdy używałem w nim parametru.

Jako szybką naprawę dodaję <base href="<yourdomain/IP>"></base> pod tagiem pliku index.html w folderze build.

I to właśnie naprawiło mój problem.

person Diwakar Prasad    schedule 02.02.2021

Miałem ten sam problem i to rozwiązanie zadziałało dla nas..

Tło:

Udostępniamy wiele aplikacji na tym samym serwerze. Kiedy odświeżymy serwer, nie będzie wiedział, gdzie szukać naszego indeksu w folderze dist dla tej konkretnej aplikacji. Powyższy link zaprowadzi Cię do tego, co dla nas zadziałało... Mam nadzieję, że to pomoże, ponieważ spędziliśmy wiele godzin na szukaniu rozwiązania dla naszych potrzeb.

Używamy:

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"
}

mój 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]
}

mój index.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')
)

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

Podoba mi się ten sposób radzenia sobie z tym. Spróbuj dodać: yourSPAPageRoute/* po stronie serwera, aby pozbyć się tego problemu.

Poszedłem z tym podejściem, ponieważ nawet natywny interfejs API historii HTML5 nie obsługuje poprawnego przekierowywania przy odświeżaniu strony (o ile wiem).

Uwaga: Wybrana odpowiedź już dotyczyła tego, ale staram się być bardziej szczegółowy.

Trasa ekspresowa

Test - History API Przetestowano i po prostu chciałem się tym podzielić.

Mam nadzieję, że to pomoże.

person Rehan    schedule 05.12.2018

Załóżmy, że masz następującą definicję trasy domowej

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

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

W komponencie Home możesz przechwycić żądanie na zdarzeniu ComponentWillMount,

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

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

Teraz, zamiast wywoływać /joblist pod adresem URL, możesz zażądać /?joblist, a składnik automatycznie przekieruje żądanie do /joblist (zwróć uwagę na dodatkowy znak zapytania w ścieżce)

person user2674595    schedule 09.07.2019

Jeśli przyjeżdżasz tutaj i używasz Apache i nie masz pliku .htaccess, to jest plik konfiguracyjny, który zadziałał dla mnie:

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

Rozwiązanie dla Preact z routerem preact

Działa z odświeżaniem i bezpośrednim dostępem

Dla tych, którzy odkrywają to przez Google, oto demonstracja historii 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="/pl/page2">page 2</a>
            </div>
            <div path="/page2">
                <p>Page Two</p>
                <a href="/pl/">back to home</a><br/>
            </div>
        </Router>
    </div>
);

jsfiddle

person keemor    schedule 05.10.2017

Oto odkryte przeze mnie rozwiązanie frontendowe, które nie wymaga modyfikacji niczego na serwerze.

Załóżmy, że Twoja witryna to mysite.com i masz ścieżkę reakcji do mysite.com/about. W index.js, gdzie montujesz komponent najwyższego poziomu, możesz umieścić inny router, taki jak:

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

Zakładam, że oryginalny router znajduje się gdzieś poniżej komponentu najwyższego poziomu w wirtualnym DOM. Musisz również złapać adres URL w swoich .urls, jeśli używasz Django, takich jak:

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

Będzie to jednak zależeć od tego, jakiego backendu używasz. Żądanie mysite/about przeniesie Cię do index.js (gdzie montujesz komponent najwyższego poziomu), gdzie możesz użyć właściwości renderowania Route, zamiast właściwości komponentu i przekazać „/about” jako właściwość w tym przykładzie składnik Home.

W Home, w haczyku componentDidMount() lub useEffect(), wykonaj:

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

Założyłem, że Twój komponent Home renderuje coś takiego:

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

Kredyt dla (Przekaż właściwości do komponentu renderowanego przez React Router) jak przekazać rekwizyty do komponentów w Routes.

person Stevie    schedule 28.07.2019

Używam .Net Core 3.1 i właśnie dodałem rozszerzenie 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

Innym sposobem żądania danych, nawet jeśli kierujesz się do adresów URL natychmiast, jest sprawienie, aby każdy komponent miał metodę, która wywołuje ostatnie parametry, takie jak /about/test, a następnie do dostawcy stanu masz funkcję który łączy się z komponentem, za pomocą którego chcesz zażądać danych

person Vince    schedule 04.06.2020

Używam trybu React.js + Webpack. Dodałem parametr --history-api-fallback w pliku package.json. Wtedy odświeżanie strony działa poprawnie. Za każdym razem, gdy zmieniam kod, strona internetowa odświeża się automatycznie.

"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

Wiem, że na to pytanie udzielono odpowiedzi na śmierć, ale to nie rozwiązuje problemu, w którym chcesz używać routera przeglądarki z proxy pass, gdzie nie możesz korzystać z roota.

Dla mnie rozwiązanie jest dość proste.

powiedz, że masz adres URL wskazujący na jakiś port.

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

a teraz z powodu podścieżek przeglądarki routera są zepsute. Jednak wiesz, jakie są podścieżki.

Rozwiązanie tego? Dla ścieżki podrzędnej /contact

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

Nic innego, co próbowałem, nie działa, ale ta prosta poprawka działa jak cholerny urok.

person danieltan95    schedule 09.11.2020

Miałem do czynienia z tym problemem w Electronie, gdy używałem Reacta do front-endu i react-router-dom do routingu. Zamieniłem BrowserRouter na HashRouter i zostało to naprawione. Oto prosty przykład

import {
  HashRouter as Router,
  Switch,
  Route,
} from "react-router-dom";
person Sanan Ali    schedule 03.06.2021
comment
nie ma potrzeby korzystania z HashRoutera, mam na to rozwiązanie, ostatnio zetknąłem się z tym problemem w projekcie, prawdopodobnie napiszę odpowiedź później, gdy będę miał czas - person Inzamam Malik; 10.07.2021
comment
jasne, chciałbym poznać twoje rozwiązanie. - person Sanan Ali; 12.07.2021

HashRouter będzie łatwą implementacją,

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

W przeglądarce będzie to coś takiego: http:localhost:3000/#/ , http:localhost:3000/#/niektóre

person lakjeewa Wijebandara    schedule 10.07.2021

Jest to dość proste, gdy nie można uzyskać błędu 403 po odświeżeniu komponentu dom. po prostu dodaj ten jeden wiersz w konfiguracji pakietu internetowego, „historyApiFallback: true”. to savez cały mój dzień.

person praveenkumar s    schedule 02.01.2018

Pełny router z przykładem (React Router v4):

Przykładowy przykład pracy Sprawdź projekt poniżej.

react-router-4-przykład

Po pobraniu
1.) "npm install" w cmd, aby zainstalować projekt
2.) "npm start", aby uruchomić aplikację React

Uwaga: potrzebujesz oprogramowania Node js do uruchomienia w swoich oknach. Mac OS ma domyślny węzeł.

Twoje zdrowie

person Muthu Kumar    schedule 29.01.2019