React-router URL'leri manuel olarak yenileme veya yazma sırasında çalışmaz


653

React-router kullanıyorum ve bağlantı düğmelerini tıklarken iyi çalışıyor, ancak web sayfamı yenilediğimde istediğimi yüklemiyor.

Mesela ben varım localhost/joblistve her şey yolunda çünkü buraya bir linke basarak geldim. Ama web sayfasını yenilersem şunu elde ederim:

Cannot GET /joblist

Varsayılan olarak, böyle çalışmadı. Başlangıçta ben olarak benim URL vardı localhost/#/ve localhost/#/joblistonlar mükemmel iyi çalıştı. Ama bu tür bir URL'yi sevmiyorum, bu yüzden silmeye çalışarak #şunu yazdım:

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

Bu sorunla karşılaşılmaz localhost/, bu her zaman istediğimi döndürür.

EDIT: Bu uygulama tek sayfadır, bu nedenle /joblistherhangi bir sunucuya bir şey sormak gerekmez.

EDIT2: Tüm yönlendiricim.

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

ana tur sayfanızı yüklemek ve yönlendiricinize location.pathname komutunu kullanmasını söylemek için htaccess kullanmadığınız sürece işe yaramaz ..
Charles John Thompson III

Bu #sembolü nasıl sildin? Teşekkür ederim!
SudoPlz

4
Reaksiyon uygulamanızı bir S3 kovasında barındırıyorsanız, hata belgesini olarak ayarlayabilirsiniz index.html. Bu, index.htmlne olursa olsun vurulduğundan emin olacaktır .
Trevor Hutto

Benim durumumda, windows iyi çalışıyor ama linux değil
Ejaz Karim

Yanıtlar:


1094

Kabul edilen cevap ve bu sorunun genel doğası ('işe yaramaz') hakkındaki yorumlara bakarak, bunun burada yer alan konular hakkında bazı genel açıklamalar için iyi bir yer olabileceğini düşündüm. Dolayısıyla bu cevap, OP'nin özel kullanım durumu hakkında arka plan bilgisi / detaylandırma olarak tasarlanmıştır. Lütfen bana eşlik et.

Sunucu tarafı ve İstemci tarafı

Bu konuda anlaşılması gereken ilk büyük şey, URL'nin yorumlandığı 2 yer olması ve 'eski günlerde' sadece 1 olmasıydı. Geçmişte, yaşam basit olduğunda, bazı kullanıcılar http://example.com/aboutsunucuya URL'nin yol bölümünü inceleyen bir istek gönderdi , kullanıcının yaklaşık sayfayı istediğini belirledi ve sonra o sayfayı geri gönderdi.

React-Router'ın sağladığı istemci tarafı yönlendirme ile işler daha az basittir. İlk başta, istemcide henüz yüklü bir JS kodu yoktur. Bu yüzden ilk istek her zaman sunucuya olacaktır. Bu daha sonra React ve React Router vb. Yüklemek için gerekli kod etiketlerini içeren bir sayfa döndürür. Örneğin 'Hakkımızda' gezinme bağlantısı tıkladığında, URL değiştiğinde faz 2, In sadece yerel olarak hiç http://example.com/about(mümkün hale Tarih API ), ancak sunucuya hiçbir istek yapıldığında. Bunun yerine, React Router işini istemci tarafında yapar, hangi React görünümünün oluşturulacağını belirler ve oluşturur. Hakkında sayfanızın herhangi bir REST çağrısı yapması gerekmediğini varsayarsak, zaten yapılır. Hiçbir sunucu isteği tetiklenmeden Ana Sayfa'dan Hakkımızda'ya geçtiniz.

Temel olarak bir bağlantıyı tıklattığınızda, sayfa yenilemesine neden olmadan adres çubuğundaki URL'yi işleyen bazı Javascript çalışır ve bu da React Router'ın istemci tarafında bir sayfa geçişi gerçekleştirmesine neden olur .

Ancak şimdi URL'yi adres çubuğuna kopyalayıp yapıştırır ve bir arkadaşınıza e-postayla gönderirseniz ne olacağını düşünün. Arkadaşınız henüz web sitenizi yüklemedi. Başka bir deyişle, hala 1. aşamadadır . Makinesinde henüz hiçbir React Router çalışmıyor. Yani onun tarayıcı bir hale getirecek Sunucu isteği için http://example.com/about.

İşte sorun burada başlıyor. Şimdiye kadar, sunucunuzun web köküne statik bir HTML yerleştirmekten kurtulabilirsiniz. Ancak bu , sunucudan istendiğinde404 diğer tüm URL'ler için hatalar verir . Aynı URL'ler istemci tarafında iyi çalışır , çünkü React Router sizin için yönlendirmeyi yapıyor, ancak sunucunuzu onları anlamadığınız sürece sunucu tarafında başarısız oluyorlar .

Sunucu ve istemci tarafı yönlendirmeyi birleştirme

http://example.com/aboutURL'nin hem sunucu hem de istemci tarafında çalışmasını istiyorsanız, hem sunucu hem de istemci tarafında bunun için yollar ayarlamanız gerekir. Mantıklı geliyor mu?

Ve seçimlerinizin başladığı yer burası. Çözümler, sorunun önyüklenmesini, önyükleme HTML'sini döndüren bir tümünü yakala yolu aracılığıyla, hem sunucunun hem de istemcinin aynı JS kodunu çalıştırdığı tam izomorfik yaklaşıma kadar uzanır.

.

Sorunu tamamen atlamak: Karma Geçmişi

Tarayıcı Geçmişi yerine Karma Geçmişi ile , yaklaşık sayfasının URL'niz şuna benzer: Hash ( ) simgesinden sonraki bölüm sunucuya gönderilmez. Böylece sunucu dizin sayfasını yalnızca beklendiği gibi görür ve gönderir. React-Router parçayı alır ve doğru sayfayı gösterir.http://example.com/#/about#http://example.com/#/about

Dezavantajları :

  • 'çirkin' URL'ler
  • Bu yaklaşımla sunucu tarafı oluşturma mümkün değildir. Arama Motoru Optimizasyonu (SEO) ile ilgili olarak, web siteniz neredeyse hiç içerik barındıran tek bir sayfadan oluşmaktadır.

.

Tümünü yakalama

Bu yaklaşım sayesinde kullanım Tarayıcı Geçmişi, ama sadece bir catch-all gönderen sunucuda kurmak /*için index.htmletkin bir size Hash Geçmişi ile hemen hemen aynı durum vererek. Bununla birlikte temiz URL'leriniz var ve daha sonra tüm kullanıcı sık kullanılanlarını geçersiz kılmak zorunda kalmadan bu şema üzerinde iyileştirebilirsiniz.

Dezavantajları :

  • Kurulumu daha karmaşık
  • Hala iyi bir SEO yok

.

melez

Karma yaklaşımda, belirli yollar için belirli komut dosyaları ekleyerek tümünü yakalama senaryosunu genişletirsiniz. İçeriğinizle birlikte sitenizin en önemli sayfalarını döndürmek için bazı basit PHP komut dosyaları oluşturabilirsiniz, böylece Googlebot en azından sayfanızda ne olduğunu görebilir.

Dezavantajları :

  • Kurulumu daha da karmaşık
  • Sadece özel tedavi verdiğiniz yollar için iyi SEO
  • Sunucuda ve istemcide içerik oluşturmak için çoğaltma kodu

.

izomorf

Her iki uçta da aynı JS kodunu çalıştırabilmemiz için Node JS'yi sunucumuz olarak kullanırsak ne olur ? Artık tüm rotalarımız tek bir tepki yönlendirici yapılandırmasında tanımlanmıştır ve oluşturma kodumuzu çoğaltmamız gerekmez. Bu tabiri caizse 'kutsal kâse'. Sunucu, sayfa geçişi istemcide gerçekleşmiş olsaydı sonuçlandırdığımız işaretin aynısını gönderir. Bu çözüm SEO açısından idealdir.

Dezavantajları :

  • Sunucu gerekir JS çalıştırın (muktedir). Java icw Nashorn ile denedim ama bu benim için çalışmıyor. Uygulamada bu çoğunlukla Node JS tabanlı bir sunucu kullanmanız gerektiği anlamına gelir.
  • Birçok zorlu çevre sorunu ( windowsunucu tarafında vb. Kullanarak )
  • Dik öğrenme eğrisi

.

Hangisini kullanmalıyım?

Kaçabileceğinizi seçin. Şahsen ben catch-all kurmak için basit olduğunu düşünüyorum, bu yüzden benim minimum olurdu. Bu kurulum, zamanla işleri iyileştirmenizi sağlar. Sunucu platformunuz olarak zaten Node JS kullanıyorsanız, kesinlikle izomorfik bir uygulama yapmayı araştırırım. Evet ilk başta zor, ama bir kez asıldıktan sonra sorunun çok zarif bir çözümü.

Temel olarak, benim için, bu belirleyici faktör olacaktır. Sunucum Düğüm JS'de çalışıyorsa, izomorfik olurdum; Aksi takdirde Catch-all çözümü için gitmek ve sadece zaman ilerledikçe ve SEO gereksinimleri talep olarak (Hybrid çözüm) genişletmek istiyorum.

React ile izomorfik ('evrensel' olarak da adlandırılır) oluşturma hakkında daha fazla bilgi edinmek isterseniz, bu konuda bazı iyi eğitimler vardır:

Ayrıca, başlamanız için bazı başlangıç ​​kitlerine bakmanızı tavsiye ederim. Teknoloji yığını için seçimlerinizle eşleşen birini seçin (unutmayın, React MVC'deki V'dir, tam bir uygulama oluşturmak için daha fazla şeye ihtiyacınız vardır). Facebook'un kendisi tarafından yayınlanan bir kitaba bakarak başlayın:

Ya da topluluk tarafından bir çoğunu seçin. Şimdi hepsini dizine eklemeye çalışan güzel bir site var:

Bunlarla başladım:

Şu anda, yukarıdaki iki başlangıç ​​kitinden esinlenilen evrensel oluşturmanın ev yapımı bir versiyonunu kullanıyorum, ancak şimdi güncel değiller.

Soruşturmanda başarılar!


2
Büyük yazı Stijn! Bir Isomorphic tepki uygulaması için bir başlangıç ​​kiti ile gitmenizi tavsiye eder misiniz? Eğer öyleyse, tercih edeceğiniz bir örnek verebilir misiniz?
Chris

1
@ Paulos3000 Hangi sunucuyu kullandığınıza bağlıdır. Temel olarak /*, HTML sayfanız için bir rota tanımlar ve yanıt verirsiniz . Buradaki zor şey, .js ve .css dosyaları için bu yolla yapılan istekleri engellemediğinizden emin olmaktır.
Stijn de Witt

2
@ Burada bazı ilgili sorular için Paulos3000 bakınız: Apache / php için , Ekspres / js için , J2E / Java için .
Stijn de Witt

1
Merhaba, karma çözümü deniyorum, ancak şans yok. Alma createMemoryHistory is not a functionhatası. Bir bakıma aldırıyor musunuz? stackoverflow.com/questions/45002573/…
Leon Gaban

5
@LeonGaban Bu yanıt yazıldığından beri React Router uygulamalarını değiştirdi. Artık farklı geçmişler için farklı Router örnekleri var ve geçmişin arka planda yapılandırılmasını yapıyorlar. Temel ilkeler hala aynı.
Stijn de Witt

115

Buradaki yanıtların hepsi son derece yararlı, benim için işe yarayan şey Webpack sunucumu rotaları bekleyecek şekilde yapılandırıyordu.

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

HistoryApiFallback bu sorunu benim için düzeltti. Şimdi yönlendirme düzgün çalışıyor ve sayfayı yenileyebilir veya doğrudan URL'yi yazabilirim. Düğüm sunucunuzdaki çalışma ortamları hakkında endişelenmenize gerek yok. Bu cevap sadece webpack kullanıyorsanız işe yarar.

EDIT: bunun neden gerekli olduğunu daha ayrıntılı bir neden için cevabımı görmek: https://stackoverflow.com/a/37622953/5217568


16
Webpack ekibinin dev sunucuyu üretimde kullanmamanızı önerdiğini unutmayın .
Stijn de Witt

5
Genel geliştirme amacıyla bu en iyi çözümdür. historyApiFallbackyeterlidir. Diğer tüm seçeneklere gelince, bayraklı CLI'den de ayarlanabilir --history-api-fallback.
Marco Lazzeri

2
@Kunok Öyle değil. Bu geliştirme için hızlı bir düzeltme ama yine de üretim için bir şeyler bulmanız gerekecek.
Stijn de Witt

contentBase: ': /' uygulama dosyalarınıza url'den erişilebildiğinden
Nezih

85

.htaccessDosyanızı değiştirebilir ve bunu ekleyebilirsiniz:

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

Ben kullanıyorum react: "^16.12.0"ve react-router: "^5.1.2" bu yöntem Catch-all ve muhtemelen başlamak için en kolay yoludur.


3
Bu iyi çalışıyor! ve uygulamanızı yeniden yapılandırmak istemiyorsanız en kolayı
mhyassin

7
Dont unutma RewriteEngine On ilk satır olarak
Kai Qing

3
Bu yanıtın bir Apache sunucusundaki yapılandırmaya atıfta bulunduğunu unutmayın. Bu bir React uygulamasının parçası değil.
Colton Hicks

Yukarıdaki cevapları anlamadım. Eğitmenlerin hiçbiri linklerimin hiç canlı çalışmayacağını söylemedi. Ancak bu basit htaccess dosyası çalıştı. Teşekkürler
Thomas Williams

Bu, next.js statik dışa aktarımı için de geçerlidir. Tomcat düğüme benzemediğinden next.js statik dışa aktarımı için bu ek yapılandırmaya ihtiyacımız var.
giri-jeedigunta

62

İçin Yönlendirici V4 tepki Kullanıcılar:

Bu sorunu diğer yanıtlarda belirtilen Karma Geçmişi tekniğiyle çözmeye çalışırsanız,

<Router history={hashHistory} >

V4'te çalışmıyor, lütfen HashRouter bunun yerine kullanın:

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

<HashRouter>
  <App/>
</HashRouter>

Referans: HashRouter


HashRouter'ın bu sorunu neden çözdüğüne dair herhangi bir ayrıntı verebilir misiniz? Verdiğiniz bağlantı benim için açıklamıyor. Ayrıca, yoldaki karma değerini gizlemenin bir yolu var mı? Ben BrowserRouter kullanıyordum ama onunla bu 404 sorunu koştu ..
Ian Smith

29

Yönlendirici, istemcide veya sunucuda gezinmenin gerçekleşmesine bağlı olarak iki farklı şekilde çağrılabilir. İstemci tarafı işlemi için yapılandırdınız. Anahtar parametre, run yönteminin ikincisidir , konumdur.

React Router Link bileşenini kullandığınızda, tarayıcıda gezinmeyi engeller ve istemci tarafında gezinme yapmak için transitionTo öğesini çağırır. HistoryLocation kullanıyorsunuz, bu nedenle adres çubuğundaki yeni URL'yi simüle ederek gezinme yanılsamasını tamamlamak için HTML5 geçmiş API'sını kullanıyor. Eski tarayıcılar kullanıyorsanız, bu işe yaramaz. HashLocation bileşenini kullanmanız gerekir.

Yenile düğmesine bastığınızda, tüm React ve React Router kodlarını atlarsınız. Sunucu isteği alır ve bir /joblistşey döndürmesi gerekir. Sunucuda run, doğru görünümü oluşturabilmesi için yönteme istenen yolu iletmeniz gerekir. Aynı rota haritasını kullanabilirsiniz, ancak muhtemelen farklı bir çağrı yapmanız gerekir Router.run. Charles'ın işaret ettiği gibi, bunu gerçekleştirmek için URL yeniden yazmayı kullanabilirsiniz. Diğer bir seçenek, tüm istekleri işlemek ve yol değerini konum bağımsız değişkeni olarak geçirmek için bir node.js sunucusu kullanmaktır.

Örneğin, ifade etmek gerekirse, şöyle görünebilir:

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

İstek yolunun iletildiğini unutmayın run. Bunu yapmak için, oluşturulan HTML'yi geçirebileceğiniz bir sunucu tarafı görünüm motoruna sahip olmanız gerekir. renderToStringReact'i sunucuda kullanırken ve çalıştırırken dikkat edilmesi gereken birkaç nokta vardır. Sayfa sunucuda oluşturulduktan sonra, uygulamanız istemciye yüklendiğinde, sunucu tarafında oluşturulmuş HTML'yi gerektiği gibi güncelleyerek yeniden oluşturulur.


2
Affedersiniz, bir sonraki ifadeyi açıklayabilir misiniz? "yenilemeye bastığınızda, tüm React ve React Router kodlarını atlarsınız?" Neden oluyor?
VB_

React router normalde yalnızca tarayıcı içindeki farklı 'yolları' işlemek için kullanılır. Bunu yapmanın iki tipik yolu vardır: eski stil karma yolu ve daha yeni geçmiş API'sı. Tarayıcı yenilemesi, istemci tarafı tepki yönlendirici kodunuzu atlayacak bir sunucu isteği yapar. Sunucudaki yolu kullanmanız gerekir (ancak yalnızca geçmiş API'sını kullanıyorsanız). Bunun için reaksiyon yönlendiricisini kullanabilirsiniz, ancak yukarıda tarif ettiğim şeye benzer bir şey yapmanız gerekir.
Todd

anladım. Ancak sunucu JS olmayan bir dilde ise nasıl olur (diyelim ki Java)?
VB_

2
üzgünüm… "root olmayan" bir rota oluşturmak için hızlı bir sunucuya ihtiyacınız olduğunu mu söylüyorsunuz? İlk olarak izomorfizmin tanımının kavramında veri getirme içermediğine şaşırdım (her ne kadar bariz bir SEO ihtiyacı olsa da - ve izomorfizm iddia ediyorsa, veri serveride İLE görünüm oluşturmak istiyorsanız işler umutsuzca karmaşıktır). Şimdi "WTF tepki" gibiyim, ciddiyim ... Yanlışsam beni düzeltin, kor / açısal / omurga bir rota oluşturmak için bir sunucu işi gerektirir mi? Rotaları kullanmak için bu şişirilmiş gereksinimi gerçekten anlamıyorum
Ben

1
Reaksiyon uygulamam izomorfik değilse reaksiyon yönlendiricideki yenilemenin çalışmadığı anlamına mı geliyor?
Matt

28

İndex.html dosyasına headaşağıdakileri ekleyin:

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

Sonra webpack dev sunucusu ile çalışırken bu komutu kullanın.

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

--history-api-fallback önemli kısım


Bu harika çalıştı! Bu çözümü nasıl bulduğunuz / bulduğunuz hakkında daha fazla bilgi edinmek için herhangi bir bağlantı var mı?
Ocak

1
Üzgünüm kardeşim. Denenmiş ve doğru deneme yanılma tekniği ile buldu.
Efe Ariaroo

Bahsetmeye değer bir temel href kullanıyorsanız /o HashRouterzaman işe yaramaz (karma yönlendirme kullanıyorsanız)
Robbie Averill

<Base href = "/"> etiketi bunu benim için yaptı. Bunun için teşekkürler. Webpack dev sunucusu / <bundle> yolundan paketi yakalamaya çalıştı ve başarısız oldu.
Malisbad

27

Bir web sitesi oluşturmak için create-tepki-uygulamasını kullandım ve burada da aynı sorunu yaşadım. Kullandığım BrowserRoutinggelen react-router-dompaketin. Bir Nginx sunucusunda çalışıyorum ve benim için ne çözdü aşağıdakileri ekliyordu/etc/nginx/yourconfig.conf

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

Bu .htaccess, Appache çalıştırmanız durumunda aşağıdakilerin eklenmesine karşılık gelir

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

Bu aynı zamanda Facebook tarafından önerilen bir çözüm gibi görünüyor ve burada bulunabilir


1
Vay be, nginx için böyle basit bir çözüm; yeni bir nginx kullanıcısı olarak cazibe gibi çalışır. Sadece kopyala-yapıştır ve gitmek güzel. Resmi fb belgelerine bağlantı için +1. Gitme zamanı.
user3773048

Kayıt için: nginx ve Angular App içeren bir AWS Örneği kullanıyorum. Bu çalışıyor.
Diego Sarmiento

beni kurtardın. dünden sorunumu düzeltmeye çalışıyordum, birkaç çözümden yoruldum ama başarısız oldum. Sonunda bana bu yönlendirici sorunu çözdü yardımcı oldu. ah çok teşekkürler kardeşim
Sharifur Robin

"Tepki": "^ 16.8.6", "tepki yönlendirici": "^ 5.0.1" için gereken farklı bir şey var mı? Bu çözümleri denedim (hem nginx hem de apache) ve çalışmıyorlar.
Mark A. Tagliaferro

Facebook bununla ilgili belgelerini değiştirmediği için sadece prosedürün aynı olduğunu varsayabilirim. Bir süredir denemedim.
Aidin

17

Bu sorununuzu çözebilir

Aynı sorunu Üretim modunda ReactJS uygulamasında da yaşadım. İşte sorunun 2 çözümü.

1. yönlendirme geçmişini tarayıcı yerine "hashHistory" olarak değiştirin

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

Şimdi komutu kullanarak uygulamayı oluşturun

sudo npm run build

Sonra inşa klasörünü var / www / klasörünüze yerleştirin, Şimdi uygulama her url'ye # etiketi eklenerek iyi çalışıyor. sevmek

localhost / # / ana sayfa localhost / # / aboutus

2.Çözüm: browserHistory kullanarak # etiketi olmadan,

Yönlendiricinizde geçmişinizi = {browserHistory} olarak ayarlayın, Şimdi sudo npm run build kullanarak oluşturun.

404 bulunamadı sayfasını çözmek için "conf" dosyasını oluşturmanız gerekir, conf dosyası böyle olmalıdır.

terminalinizi açın aşağıdaki komutları yazın

cd / etc / apache2 / sites-available ls nano sample.conf İçine aşağıdaki içeriği ekleyin.

<VirtualHost *:80>
    ServerAdmin admin@0.0.0.0
    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>

Şimdi aşağıdaki komutu kullanarak sample.conf dosyasını etkinleştirmeniz gerekiyor

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

o zaman sudo service apache2 reload ya da restart kullanarak apache sunucusunu yeniden yüklemenizi isteyecektir

sonra localhost / build klasörünüzü açın ve .htaccess dosyasını aşağıdaki içeriğe ekleyin.

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

Şimdi uygulama normal çalışıyor.

Not: 0.0.0.0 ip'i yerel ip adresinizle değiştirin.

Bununla ilgili herhangi bir şüpheniz varsa yorum yapmaktan çekinmeyin.

Umarım başkalarına yardımcı olur.


İlk çözüm işe yarayacak "react-router-dom": "^5.1.2"<BrowserRouter>
?, Kullanıyorum

16

AWS Static S3 Hosting & CloudFront aracılığıyla bir tepki uygulaması barındırıyorsanız

Bu sorun, CloudFront tarafından 403 Erişim Reddedildi iletisi ile yanıt verdi, çünkü S3 klasörümde / some / other / yolunun bulunması bekleniyordu, ancak bu yol yalnızca React'in reat-router ile yönlendirmesinde var.

Çözüm, bir dağıtım Hata Sayfaları kuralı oluşturmaktı. CloudFront ayarlarına gidin ve dağıtımınızı seçin. Ardından "Hata Sayfaları" sekmesine gidin. "Özel Hata Yanıtı Oluştur" u tıklayın ve aldığımız hata durum kodu olduğundan 403 için bir giriş ekleyin. Yanıt Sayfası Yolunu /index.html ve durum kodunu 200 olarak ayarlayın. Sonuç, basitliğiyle beni şaşırtıyor. Dizin sayfası sunulur, ancak URL tarayıcıda korunur, bu nedenle reaksiyon uygulaması yüklendikten sonra URL yolunu algılar ve istenen rotaya gider.

Hata Sayfaları 403 Kural


1
Tam da ihtiyacım olan şey bu. Teşekkür ederim.
Jonathan

Yani .. tüm URL'leriniz çalışıyor, ancak 403 durum kodunu döndürüyor musunuz? Doğru değil. Beklenen durum kodları 2xx aralığında olmalıdır.
Stijn de Witt

@StijndeWitt Doğru anladığınızdan emin değilim. CloudFront her şeyi halleder - istemci 403 durum kodu görmez. Yeniden yönlendirme sunucu tarafında gerçekleşir, dizin sayfasını oluşturur, URL'yi korur ve sonuç olarak doğru yolu sağlar.
th3morg

@ th3morg Ah evet şimdi görüyorum. Yanıt durumu kodunu 200 olarak doldurmanıza da izin vermeyi kaçırdım. Yani temel olarak durum 403'ü durum 200 ile eşliyorsunuz ... İyi görünüyor ... belki başka bir nedenden dolayı 403 sonuç alırsanız bu yüzden göremezsiniz.
Stijn de Witt

1
Bu @ th3morg için teşekkürler. Bu kurulum çok düzeyli yollar için de çalışır mı? Kök düzeyinde etki alanı / kaydolma, etki alanı / oturum açma, etki alanı / <documentId> gibi herhangi bir yol varsa benim için harika çalışır, ancak etki alanı / belge / <documentId> gibi çok düzeyli yollar için çalışmaz.
Pargles

16

Webpack Dev Server'ın bunu etkinleştirme seçeneği vardır. Aç package.jsonve ekle--history-api-fallback . Bu çözümler benim için çalıştı.

tepki-yönlendirici-öğretici


3
Sorun webpack-dev-serverdeğil ama bunu üretim üretimi için nasıl düzeltebilirim?
Hussain

12

Reaksiyon uygulamanızı IIS'de barındırıyorsanız, aşağıdakileri içeren bir web.config dosyası ekleyin:

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

Bu, IIS sunucusuna ana sayfayı 404 hatası yerine istemciye döndürmesini ve karma geçmişini kullanmaya gerek duymamasını söyler.


sağ ol, kanka!!!! Çalışıyor!
Thanh Bao

12

Bunu şuraya ekle webpack.config.js:

devServer: {
    historyApiFallback: true
}

Bu dev için harika, ancak üretim yapılarına yardımcı olmuyor.
KFunk

11

Üretim yığını: React, React Router v4, BrowswerRouter, Express, Nginx

1) Güzel URL'ler için Kullanıcı BrowserRouter

// app.js

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

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

2) Kullanarak bilinmeyen tüm isteklere index.html ekleyin /*

// 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) paket webpack ile webpack -p

4) çalıştırın nodemon server.jsveyanode server.js

EDIT: nginx bunu sunucu bloğunda işlemesine izin vermek ve 2. adımı göz ardı etmek isteyebilirsiniz:

location / {
    try_files $uri /index.html;
}

undefined
Goutham

@Goutham server.js dosyanızın en üstüne şunu ekleyin import path from 'pathveyaconst path = require('path')
Isaac Pak

adım 2 (hepsini yakala /*) az önce günümü kurtardı. Teşekkür ederim! :)
Atlas7

Bu, redux kullanan ve bağlı bir yönlendirici ile ilgilenen insanlar için bu örneğe bakın: github.com/supasate/connected-react-router/tree/master/examples/…
cjjenkinson

10

Create React App kullanıyorsanız:

Create React App sayfasında BURAYA bulabileceğiniz birçok büyük barındırma platformunun çözümleriyle bu konuyla ilgili harika bir yürüyüş var . Örneğin, ön uç kodum için React Router v4 ve Netlify kullanıyorum. Tek gereken ortak klasöre ("_redirects") 1 dosya ve bu dosyadaki bir kod satırı eklemekti:

/*  /index.html  200

Artık web sitem tarayıcıya girildiğinde veya birileri yenilendiğinde mysite.com/pricing gibi yolları düzgün bir şekilde oluşturuyor.


7

Aşağıdaki kodla ortak klasörün içine ".htaccess" dosyasını eklemeyi deneyin.

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

RewriteRule ^ /index.html [L]  

Teşekkürler, Fedora 28'de apache ile benim için işe yarayan buydu. Yukarıdaki yeniden yazma kurallarının hiçbiri veya CRA sayfasındaki kurallar benim için çalışmadı. Bunları ayrı bir .htaccess dosyası yerine sanal ana bilgisayar kurulumuna ekledim.
boerre

6

İndex.html dosyanızın yedeği varsa, index.html dosyanızda aşağıdakilere sahip olduğunuzdan emin olun:

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

Bu projeden projeye değişebilir.


2
Bunu head
html'nize

4

Firebase kullanıyorsanız, yapmanız gereken tek şey, uygulamanızın kökündeki (barındırma bölümünde) firebase.json dosyanızda bir yeniden yazma özelliği bulunduğundan emin olmaktır.

Örneğin:

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

Umarım bu bir başkasını bir hayal kırıklığı biriktirir ve zaman kaybettirir.

Mutlu kodlama ...

Konuyla ilgili daha fazla okuma:

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

Firebase CLI: "Tek sayfalık bir uygulama olarak yapılandır (tüm URL'leri /index.html olarak yeniden yaz)"


Sen bir efsanesin
Perniferous


3

Henüz sunucu tarafı oluşturma kullanmıyorum ama Bağlantı çoğu zaman iyi görünüyordu ama bir parametre vardı başarısız OP gibi aynı sorunu vurdu. Burada kimseye yardım edip etmediğini görmek için çözümümü belgeleyeceğim.

Benim ana jsx içerir:

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

İlk eşleşen bağlantı için bu iyi çalışır, ancak: id değiştiğinde <Link> bu modelin ayrıntı sayfasında yuvalanan ifadelerde , tarayıcı çubuğundaki URL değişir, ancak sayfanın içeriği başlangıçta bağlı modeli yansıtacak şekilde değişmez.

Sorun, props.params.idmodeli ayarlamak için kullanmış olmamdı componentDidMount. Bileşen sadece bir kez monte edildiğinden, bu, ilk modelin sayfaya yapışan model olduğu anlamına gelir ve sonraki Bağlantılar, dikmeleri değiştirir, ancak sayfayı değiştirmeden bırakır.

Modeli her ikisinde de bileşen durumunda ayarlama componentDidMount ve componentWillReceiveProps(bir sonraki sahne dayanmaktadır) sorunu çözer ve sayfa içeriği istenen modeli yansıtacak şekilde değişir.


1
Sunucu tarafı oluşturma işlemini denemek istiyorsanız, propsiso bileşenini (erişimi de vardır ) kullanmak daha iyi olabilir componentDidMount. Çünkü componentDidMountsadece tarayıcıda çağrılır. Amacı, DOM ile olay dinleyicileri ekleyemediğiniz gibi şeyler bodyyapmaktır render.
Stijn de Witt

3

Bu konu biraz eski ve çözüldü ama size basit, net ve daha iyi bir çözüm önermek istiyorum. Web sunucusu kullanıyorsanız çalışır.

Her web sunucusu http 404 durumunda kullanıcıyı bir hata sayfasına yönlendirebilir. Bu sorunu çözmek için kullanıcıyı dizin sayfasına yönlendirmeniz gerekir.

Java temel sunucusu (tomcat veya herhangi bir java uygulama sunucusu) kullanıyorsanız çözüm aşağıdaki olabilir:

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>

Misal:

  • GET http://example.com/about
  • Web sunucusu http 404 atar, çünkü bu sayfa sunucu tarafında mevcut değildir
  • hata sayfası yapılandırması sunucuya index.jsp sayfasını kullanıcıya gönderir
  • istemci tarafındaki URL hala http://example.com/about olduğundan JS işin geri kalanını clien tarafında yapar .

Hepsi bu, büyü ihtiyacı yok :)


Bu harikaydı! Wildfly 10.1 sunucusunu kullanıyorum ve bu güncellemeyi web.xml dosyama yaptım, ancak konum '/' olarak ayarlanmıştım. Çünkü benim tepki const browserHistory = useRouterHistory(createHistory)({ basename: '/<appname>' });
Chuck L

1
Bunun SEO'yu etkilemediğinden emin misiniz? Gerçekten var olan sayfalara 404 durumu veriyorsunuz. Kullanıcı bunu asla anlayamayabilir, ancak botlar sayfanızı kazımayacaklarına çok fazla dikkat eder.
subharb

3

Express'i veya arka uçta başka bir çerçeve kullanıyorsanız, aşağıdaki gibi benzer yapılandırmayı ekleyebilir ve yapılandırmadaki Webpack genel yolunu kontrol edebilirsiniz, BrowserRouter kullanıyorsanız yeniden yüklemede bile iyi çalışmalıdır.

expressApp.get('/*', (request, response) => {
    response.sendFile(path.join(__dirname, '../public/index.html'));
});

bu en basit çözüm. Bu rotanın tümünü yakalama gibi diğer rotalardan sonra gitmesi gerektiğini unutmayın
dcsan

3

Yenilemede veya URL'yi doğrudan çağırırken "GET / URL alınamıyor" hatasını düzeltmek.

Webpack.config.js dosyanızı verilen bağlantının bu gibi güzergahlar beklemesini sağlayacak şekilde yapılandırın .

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

2

Net Core MVC kullandığım gibi böyle bir şey bana yardımcı oldu:

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

Temel olarak MVC tarafında, eşleşmeyen tüm rotalar Home/Indexbelirtildiği gibi düşecektir startup.cs. İçinde Indexorijinal istek url'sini almak ve gerektiğinde geçmek mümkündür.

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

Web API'si uygulamadan ayrılırsa bunu nasıl halledeceksiniz?
dayanrr91

@ dayanrr91 Projenizde web api varsa, yine de sunucu tarafı yönlendirmesine ihtiyacınız olmayacaktır. Ve reaksiyon yönlendiricinizin URL'yi okuması ve uygun yönlendirmeyi yapması gerektiğine inanıyorum. Hiçbir şey onu engellememelidir
Elnoor

yorumunuz çok takdir ediliyor, ama sonra bir sorum var, sadece HashRouter ekledim, ancak şimdi herhangi bir URL'ye manuel olarak girdiğimde, evime ve daha sonra yapmaya çalıştığım bileşene yönlendirmek yerine ev bileşenime yönlendirilecek içeri girmek, bunun için bir çözüm var mı?
dayanrr91

@ dayanrr91 gerçekten bir fikrim yok, hashrouter hiç denemedim ama bence kodunuzla ilgili bir şey olmalı. Karma yönlendiricinin çalışma şekli tarayıcı yönlendiriciye benzer olmalıdır. Ayrıca burada sadece bu sanal alanda test ettim , iyi codesandbox.io/s/25okp1mny çalışır , url 25okp1mny.codesandbox.io/#/roster/5
Elnoor

2

IIS'de barındırıyorsanız; Bunu webconfig'ime eklemek sorunumu çözdü

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

Başka herhangi bir sunucu için benzer yapılandırma yapabilirsiniz


1

Durumunda, herkes Laravel ile React JS SPA'da çözüm arıyor. Kabul edilen cevap, bu tür sorunların neden meydana geldiğinin en iyi açıklamasıdır. Daha önce açıklandığı gibi, hem istemci tarafı hem de sunucu tarafını yapılandırmanız gerekir. Blade şablonunuza, js paketli dosyayı ekleyin, URL facadeböyle kullandığınızdan emin olun

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

Rotalarınızda, bunu bıçak şablonunun bulunduğu ana uç noktaya ekleyin. Örneğin,

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

Yukarıdaki, bıçak şablonu için ana uç noktadır. Şimdi isteğe bağlı bir rota da ekleyin,

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

Sorun, önce blade şablonunun, ardından tepki yönlendiricisinin yüklenmesidir. Yani, '/setting-alerts'yüklediğinizde, html ve js'yi yükler. Ancak '/setting-alerts/about'yüklediğinizde, önce sunucu tarafına yüklenir. Sunucu tarafında, bu konumda hiçbir şey olmadığından, bulunamadı bulunamadı. Bu isteğe bağlı yönlendiriciye sahip olduğunuzda, aynı sayfayı yükler ve tepki yönlendiricisi de yüklenir, ardından tepki yükleyici hangi bileşenin gösterileceğine karar verir. Bu yardımcı olur umarım.


Sunucuya tam bir URI'ye yüklenip sunucu Tepki'ye yeniden yönlendirilebilir mi? Örneğin, yüklediğimde /user/{userID}, sadece evrensel bir /userHTML görünümü döndürmem , kimliği getirmem ve AJAX veya axios kullanarak çağırmam gerekiyor. Bunu yapmak mümkün mü? SEO dostular mı?
Ryuujo

1

IIS 10'u kullananlar için, bunu doğru yapmak için yapmanız gereken budur. Bununla browserHistory kullandığınızdan emin olun. Referans için yönlendirme kodunu vereceğim, ancak bu önemli değil, önemli olan aşağıdaki bileşen kodundan sonraki adımdır:

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

Sorun, IIS'nin istemci tarayıcılardan istek alması nedeniyle, URL'yi bir sayfa istiyormuş gibi yorumlayacak ve kullanılabilir sayfa olmadığından 404 sayfa döndürecektir. Aşağıdakileri yapın:

  1. IIS'yi aç
  2. Server'ı genişletin, ardından Sites Klasörünü açın
  3. Web sitesini / uygulamayı tıklayın
  4. Hata Sayfalarına Git
  5. Listede 404 hata durumu öğesini açın
  6. "Statik dosyadaki içeriği hata yanıtına ekle" seçeneği yerine "Bu sitede bir URL yürüt" olarak değiştirin ve URL'ye "/" eğik çizgi değeri ekleyin.

Ve şimdi iyi çalışacak.

resim açıklamasını buraya girin resim açıklamasını buraya girin

Umut ediyorum bu yardım eder. :-)


1

WebPack kullanıyorum, aynı sorun yaşadım Solution => server.js dosyanızda

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

Uygulamam yenilendikten sonra neden oluşturulmuyor?


Bu benim için yaptı! Başlangıçta res.sendFile (path.JOIN (publicPath, "index.html")) vardı; Yukarıdaki örnekte olduğu gibi "birleştirme" yi "çözüldü" olarak değiştirdim: res.sendFile (path.resolve ("./ dist", "index.html")); Ayrıca __dirname ile oynuyordum ama gerçekten anlayamadım ya da çalıştıramadım, bu yüzden manuel olarak "./dist" içinde kopyalandım, çünkü burası index.html'nin sunulduğu yer. Ben de daha önce böyle ilan ettim: app.use (express.static ("./ dist"));
logixplayer

1

ReduxHashRouter ile benim için çalıştı kullanarak , sadece değiştirin:

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

için:

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

0

Aynı sorunu yaşadım ve bu çözüm bizim için çalıştı.

Arka fon:

Aynı sunucuda birden fazla uygulama barındırıyoruz. Ne zaman biz yenilemek sunucu belirli bir uygulama için dist klasöründe dizinimizi nerede arayacağını anlamazdı. Yukarıdaki bağlantı sizi bizim için işe yarayacaktır ... Umarım bu yardımcı olur, çünkü ihtiyaçlarımız için bir çözüm bulmak için oldukça fazla saat harcadık.

Kullanıyoruz:

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

webpack.config.js dosyam

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

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

benim app.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!');
});

0

Bunu idare etmeyi seviyorum. Bu sorundan kurtulmak için sunucu tarafına SPAPageRoute / * eklemeyi deneyin .

Yerel HTML5 Geçmiş API'sı bile sayfa yenilemede doğru yönlendirmeyi desteklemediğinden (bildiğim kadarıyla) bu yaklaşıma gittim.

Not: Seçilen cevap zaten bunu ele aldı ama ben daha spesifik olmaya çalışıyorum.

Hızlı Rota

Test - Geçmiş API'sı Test edildi ve sadece bunu paylaşmak istedim.

Umarım yardımcı olur.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.