Các url của bộ định tuyến không hoạt động khi làm mới hoặc viết thủ công


655

Tôi đang sử dụng React-router và nó hoạt động tốt trong khi tôi nhấp vào các nút liên kết, nhưng khi tôi làm mới trang web của mình thì nó không tải những gì tôi muốn.

Ví dụ, tôi đang ở localhost/joblistvà mọi thứ đều ổn vì tôi đến đây nhấn một liên kết. Nhưng nếu tôi làm mới trang web tôi nhận được:

Cannot GET /joblist

Theo mặc định, nó không hoạt động như thế này. Ban đầu tôi đã URL của tôi là localhost/#/localhost/#/joblistvà họ làm việc hoàn toàn tốt đẹp. Nhưng tôi không thích loại URL này, vì vậy cố gắng xóa nó #, tôi đã viết:

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

Vấn đề này không xảy ra với localhost/, vấn đề này luôn trả về những gì tôi muốn.

EDIT: Ứng dụng này là một trang, vì vậy /joblistkhông cần phải hỏi bất cứ điều gì với bất kỳ máy chủ nào.

EDIT2: Toàn bộ bộ định tuyến của tôi.

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

trừ khi bạn sử dụng htaccess để tải trang tham quan chính của mình và báo cho bộ định tuyến của bạn sử dụng location.pathname nó sẽ không hoạt động ..
Charles John Thompson III

Làm thế nào bạn xóa #biểu tượng đó ? Cảm ơn bạn!
SudoPlz

4
Nếu bạn đang lưu trữ ứng dụng phản ứng của mình trong nhóm S3, bạn chỉ cần đặt tài liệu lỗi thành index.html. Điều này sẽ đảm bảo index.htmlđược nhấn bất kể điều gì.
Trevor Hutto

Trong trường hợp của tôi, nó hoạt động tốt trong windows nhưng không phải trong linux
Ejaz Karim

Đây là tài liệu tham khảo giúp giải quyết vấn đề của tôi: github.com/facebook/create-react-app/blob/master/packages/
mẹo

Câu trả lời:


1096

Nhìn vào các ý kiến ​​về câu trả lời được chấp nhận và bản chất chung của câu hỏi này ('không hoạt động'), tôi nghĩ rằng đây có thể là một nơi tốt cho một số giải thích chung về các vấn đề liên quan ở đây. Vì vậy, câu trả lời này được dự định là thông tin cơ bản / chi tiết về trường hợp sử dụng cụ thể của OP. Xin vui lòng chịu với tôi.

Phía máy chủ và phía máy khách

Điều quan trọng đầu tiên cần hiểu về điều này là hiện tại có 2 địa điểm mà URL được diễn giải, trong khi trước đây chỉ có 1 trong 'ngày xưa'. Trước đây, khi cuộc sống đơn giản, một số người dùng đã gửi yêu cầu http://example.com/aboutđến máy chủ, đã kiểm tra phần đường dẫn của URL, xác định người dùng đang yêu cầu trang about và sau đó gửi lại trang đó.

Với định tuyến phía máy khách, đó là những gì React-Router cung cấp, mọi thứ trở nên đơn giản hơn. Lúc đầu, máy khách chưa có bất kỳ mã JS nào được tải. Vì vậy, yêu cầu đầu tiên sẽ luôn luôn là máy chủ. Điều đó sau đó sẽ trả về một trang có chứa các thẻ script cần thiết để tải React và React Router, v.v. Chỉ khi các script đó được tải thì giai đoạn 2 mới bắt đầu. Trong giai đoạn 2, khi người dùng nhấp vào liên kết điều hướng 'Giới thiệu về chúng tôi', URL chỉ được thay đổi cục bộ thành http://example.com/about(được thực hiện bởi API Lịch sử ), nhưng không có yêu cầu nào đối với máy chủ được thực hiện. Thay vào đó, React Router thực hiện công việc của mình ở phía máy khách, xác định chế độ xem React nào sẽ hiển thị và kết xuất lại. Giả sử trang về của bạn không cần thực hiện bất kỳ cuộc gọi REST nào, nó đã được thực hiện. Bạn đã chuyển từ Trang chủ sang Giới thiệu mà không yêu cầu máy chủ nào thực hiện.

Vì vậy, về cơ bản khi bạn nhấp vào một liên kết, một số Javascript chạy thao tác URL trong thanh địa chỉ mà không gây ra làm mới trang , điều này sẽ khiến React Router thực hiện chuyển đổi trang ở phía máy khách .

Nhưng bây giờ hãy xem xét điều gì xảy ra nếu bạn sao chép-dán URL vào thanh địa chỉ và gửi email cho bạn bè. Bạn của bạn chưa tải trang web của bạn. Nói cách khác, cô ấy vẫn ở giai đoạn 1 . Chưa có React Router nào đang chạy trên máy của cô ấy. Vì vậy, trình duyệt của mình sẽ làm cho một yêu cầu máy chủ để http://example.com/about.

Và đây là lúc rắc rối của bạn bắt đầu. Cho đến bây giờ, bạn có thể thoát khỏi việc chỉ cần đặt một HTML tĩnh tại webroot của máy chủ của bạn. Nhưng điều đó sẽ gây ra 404lỗi cho tất cả các URL khác khi được yêu cầu từ máy chủ . Các URL tương tự đó hoạt động tốt ở phía máy khách , vì có React Router đang thực hiện định tuyến cho bạn, nhưng chúng không thành công ở phía máy chủ trừ khi bạn làm cho máy chủ của bạn hiểu chúng.

Kết hợp định tuyến phía máy chủ và máy khách

Nếu bạn muốn http://example.com/aboutURL hoạt động trên cả máy chủ- và phía máy khách, bạn cần thiết lập các tuyến đường cho nó trên cả máy chủ - và phía máy khách. Làm cho ý nghĩa phải không?

Và đây là nơi lựa chọn của bạn bắt đầu. Các giải pháp bao gồm từ bỏ qua vấn đề hoàn toàn, thông qua một lộ trình bắt tất cả trả về HTML bootstrap, đến cách tiếp cận đẳng cấu đầy đủ trong đó cả máy chủ và máy khách đều chạy cùng một mã JS.

.

Bỏ qua vấn đề hoàn toàn: Lịch sử Hash

Với Lịch sử băm thay vì Lịch sử trình duyệt , URL của bạn cho trang giới thiệu sẽ trông giống như thế này: http://example.com/#/about Phần sau #biểu tượng băm ( ) không được gửi đến máy chủ. Vì vậy, máy chủ chỉ nhìn thấy http://example.com/và gửi trang chỉ mục như mong đợi. React-Router sẽ chọn #/aboutphần và hiển thị trang chính xác.

Nhược điểm :

  • URL 'xấu xí'
  • Kết xuất phía máy chủ là không thể với phương pháp này. Theo như Công cụ Tìm kiếm Tối ưu hóa (SEO) có liên quan, trang web của bạn bao gồm một trang duy nhất với hầu như không có bất kỳ nội dung nào trên đó.

.

Bắt hết

Với phương pháp này, bạn có thể sử dụng Lịch sử trình duyệt, nhưng chỉ cần thiết lập một bản tóm tắt trên máy chủ gửi /*đến index.html, mang lại cho bạn nhiều tình huống tương tự như với Lịch sử Hash. Tuy nhiên, bạn có URL sạch và bạn có thể cải thiện chương trình này sau mà không phải làm mất hiệu lực tất cả các mục yêu thích của người dùng.

Nhược điểm :

  • Thiết lập phức tạp hơn
  • Vẫn không có SEO tốt

.

Hỗn hợp

Trong phương pháp kết hợp, bạn mở rộng theo kịch bản bắt tất cả bằng cách thêm các tập lệnh cụ thể cho các tuyến cụ thể. Bạn có thể tạo một số tập lệnh PHP đơn giản để trả về các trang quan trọng nhất của trang web của bạn có nội dung được bao gồm, do đó, Googlebot ít nhất có thể nhìn thấy những gì trên trang của bạn.

Nhược điểm :

  • Thậm chí phức tạp hơn để thiết lập
  • Chỉ SEO tốt cho những tuyến đường bạn cung cấp cho điều trị đặc biệt
  • Mã trùng lặp để hiển thị nội dung trên máy chủ và máy khách

.

Đồng phân

Điều gì xảy ra nếu chúng ta sử dụng Node JS làm máy chủ của mình để chúng ta có thể chạy cùng một mã JS ở cả hai đầu? Bây giờ, chúng tôi có tất cả các tuyến đường được xác định trong một cấu hình bộ định tuyến phản ứng và chúng tôi không cần sao chép mã kết xuất. Đây là 'chén thánh' để nói. Máy chủ sẽ gửi đánh dấu chính xác giống như chúng ta sẽ kết thúc nếu quá trình chuyển trang xảy ra trên máy khách. Giải pháp này là tối ưu về mặt SEO.

Nhược điểm :

  • Máy chủ phải (có thể) chạy JS. Tôi đã thử nghiệm với Java icw Nashorn nhưng nó không hoạt động với tôi. Trong thực tế, điều đó có nghĩa là bạn phải sử dụng máy chủ dựa trên Node JS.
  • Nhiều vấn đề môi trường phức tạp (sử dụng windowở phía máy chủ, v.v.)
  • Dốc học

.

Tôi nên sử dụng cái nào?

Chọn một trong đó bạn có thể đi với. Cá nhân tôi nghĩ rằng bắt tất cả là đủ đơn giản để thiết lập, vì vậy đó sẽ là tối thiểu của tôi. Thiết lập này cho phép bạn cải thiện mọi thứ theo thời gian. Nếu bạn đã sử dụng Node JS làm nền tảng máy chủ của mình, tôi chắc chắn sẽ điều tra làm một ứng dụng đẳng cấu. Vâng, ban đầu nó rất khó khăn, nhưng một khi bạn hiểu rõ thì đó thực sự là một giải pháp rất hay cho vấn đề.

Về cơ bản, đối với tôi, đó sẽ là yếu tố quyết định. Nếu máy chủ của tôi chạy trên Node JS, tôi sẽ chuyển sang dạng đồng phân; nếu không, tôi sẽ sử dụng giải pháp Catch-all và chỉ mở rộng trên nó (giải pháp lai) khi tiến độ thời gian và yêu cầu SEO yêu cầu nó.

Nếu bạn muốn tìm hiểu thêm về kết xuất đẳng cấu (còn gọi là 'phổ quát') với React, có một số hướng dẫn tốt về chủ đề này:

Ngoài ra, để giúp bạn bắt đầu, tôi khuyên bạn nên xem xét một số bộ dụng cụ khởi động. Chọn một lựa chọn phù hợp với lựa chọn của bạn cho ngăn xếp công nghệ (hãy nhớ, React chỉ là V trong MVC, bạn cần nhiều thứ hơn để xây dựng một ứng dụng đầy đủ). Bắt đầu bằng cách nhìn vào một cái được xuất bản bởi chính Facebook:

Hoặc chọn một trong số nhiều bởi cộng đồng. Hiện tại có một trang web đẹp cố gắng lập chỉ mục tất cả chúng:

Tôi bắt đầu với những điều này:

Hiện tại tôi đang sử dụng một phiên bản sản xuất bia phổ biến tại nhà được lấy cảm hứng từ hai bộ dụng cụ khởi động ở trên, nhưng chúng đã lỗi thời.

Chúc may mắn với tìm kiếm của bạn!


2
Bài tuyệt vời Stijn! Bạn có muốn giới thiệu với một bộ khởi động cho một ứng dụng phản ứng đẳng hình? Nếu vậy, bạn có thể đưa ra một ví dụ về một cái bạn muốn?
Chris

1
@ Paulos3000 Nó phụ thuộc vào máy chủ bạn đang sử dụng. Về cơ bản, bạn xác định lộ trình /*và làm cho nó phản hồi với trang HTML của bạn. Điều khó khăn ở đây là đảm bảo rằng bạn không chặn các yêu cầu đối với các tệp .js và .css với tuyến đường này.
Stijn de Witt

2
@ Paulos3000 Xem tại đây để biết một số câu hỏi liên quan: cho Apache / php , cho Express / js , cho J2E / Java .
Stijn de Witt

1
Xin chào, tôi đang thử giải pháp băm, tuy nhiên không có may mắn. Bắt createMemoryHistory is not a functionlỗi. Tâm trí một cái nhìn? stackoverflow.com/questions/45002573/
Mạnh

5
@LeonGaban Có vẻ như vì câu trả lời này đã được viết, React Router đã thay đổi cách thực hiện của họ. Bây giờ họ có các phiên bản Bộ định tuyến khác nhau cho các lịch sử khác nhau và họ thực hiện cấu hình lịch sử trong nền. Các nguyên tắc cơ bản là như nhau vẫn còn.
Stijn de Witt

116

Các câu trả lời ở đây đều rất hữu ích, điều làm việc cho tôi là cấu hình máy chủ Webpack của tôi để mong đợi các tuyến đường.

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

Lịch sửApiFallback là những gì đã khắc phục vấn đề này cho tôi. Bây giờ định tuyến hoạt động chính xác và tôi có thể làm mới trang hoặc nhập URL trực tiếp. Không cần phải lo lắng về công việc xung quanh máy chủ nút của bạn. Câu trả lời này rõ ràng chỉ hoạt động nếu bạn đang sử dụng webpack.

EDIT: xem câu trả lời của tôi ở đây để biết lý do chi tiết hơn tại sao điều này lại cần thiết: https://stackoverflow.com/a/37622953/5217568


16
Xin lưu ý rằng nhóm Webpack khuyên bạn không nên sử dụng máy chủ dev trong sản xuất.
Stijn de Witt

5
Đối với mục đích phát triển chung đây là giải pháp tốt nhất. historyApiFallbacklà đủ. Đối với tất cả các tùy chọn khác, nó cũng có thể được đặt từ CLI với cờ --history-api-fallback.
Marco Lazzeri

2
@Kunok Không. Đây là một sửa chữa nhanh chóng để phát triển nhưng bạn vẫn sẽ phải tìm ra một cái gì đó cho sản xuất.
Stijn de Witt

contentBase: ': /' vì các tệp ứng dụng của bạn có thể được truy cập từ url
Nezih

85

Bạn có thể thay đổi .htaccesstập tin của bạn và chèn này:

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

Tôi đang sử dụng react: "^16.12.0"react-router: "^5.1.2" Phương pháp này là Catch-all và có lẽ là cách dễ nhất để bạn bắt đầu.


3
Điều này hoạt động tốt! và dễ nhất nếu bạn không muốn cơ cấu lại ứng dụng của mình
mhyassin

7
Đừng quên RewriteEngine On là dòng đầu tiên
Kai Qing

3
Lưu ý câu trả lời này đề cập đến cấu hình trên máy chủ Apache. Đây không phải là một phần của ứng dụng React.
Colton Hicks

Tôi không hiểu câu trả lời ở trên. Không ai trong số các gia sư nói rằng các liên kết của tôi sẽ không hoạt động. Tuy nhiên tập tin htaccess đơn giản này đã làm việc. Cảm ơn
Thomas Williams

Điều này cũng hoạt động cho xuất tĩnh next.js. Vì tomcat không giống với nút, chúng tôi cần cấu hình bổ sung này cho xuất khẩu tĩnh next.js.
giri-jeedigunta

62

Đối với người dùng React Router V4 :

Nếu bạn cố gắng giải quyết vấn đề này bằng kỹ thuật Lịch sử Hash được đề cập trong các câu trả lời khác, hãy lưu ý rằng

<Router history={hashHistory} >

không hoạt động trong V4, vui lòng sử dụng HashRouterthay thế:

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

<HashRouter>
  <App/>
</HashRouter>

Tham khảo: HashRouter


Bạn có thể cung cấp bất kỳ chi tiết nào về lý do tại sao HashRouter khắc phục vấn đề này? Liên kết bạn cung cấp không giải thích cho tôi. Ngoài ra, có cách nào để ẩn băm trong đường dẫn không? Tôi đã sử dụng BrowserRouter nhưng gặp phải sự cố 404 này với nó ..
Ian Smith

29

Bộ định tuyến có thể được gọi theo hai cách khác nhau, tùy thuộc vào việc điều hướng xảy ra trên máy khách hay trên máy chủ. Bạn đã cấu hình nó cho hoạt động phía máy khách. Tham số chính là cái thứ hai cho phương thức chạy , vị trí.

Khi bạn sử dụng thành phần Liên kết Bộ định tuyến React, nó sẽ chặn điều hướng trình duyệt và gọi quá trình chuyển đổi để thực hiện điều hướng phía máy khách. Bạn đang sử dụng HistoryLocation, do đó, nó sử dụng API lịch sử HTML5 để hoàn thành ảo ảnh điều hướng bằng cách mô phỏng URL mới trong thanh địa chỉ. Nếu bạn đang sử dụng các trình duyệt cũ hơn, điều này sẽ không hoạt động. Bạn sẽ cần sử dụng thành phần HashLocation.

Khi bạn nhấn refresh, bạn bỏ qua tất cả mã Bộ định tuyến và Phản ứng. Máy chủ nhận được yêu cầu /joblistvà nó phải trả lại một cái gì đó. Trên máy chủ, bạn cần chuyển đường dẫn được yêu cầu tới runphương thức để hiển thị đúng chế độ xem. Bạn có thể sử dụng cùng một bản đồ lộ trình, nhưng có lẽ bạn sẽ cần một cuộc gọi khác đểRouter.run . Như Charles chỉ ra, bạn có thể sử dụng viết lại URL để xử lý việc này. Một tùy chọn khác là sử dụng máy chủ node.js để xử lý tất cả các yêu cầu và chuyển giá trị đường dẫn làm đối số vị trí.

Ví dụ, trong biểu thức, nó có thể trông như thế này:

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

Lưu ý rằng đường dẫn yêu cầu đang được chuyển đến run. Để làm điều này, bạn sẽ cần phải có một công cụ xem phía máy chủ mà bạn có thể chuyển HTML được kết xuất sang. Có một số cân nhắc khác khi sử dụng renderToStringvà khi chạy React trên máy chủ. Khi trang được hiển thị trên máy chủ, khi ứng dụng của bạn tải vào máy khách, nó sẽ hiển thị lại, cập nhật HTML kết xuất phía máy chủ khi cần.


2
Xin lỗi, tôi có thể giải thích câu lệnh tiếp theo "khi bạn nhấn refresh, bạn bỏ qua tất cả mã Bộ định tuyến React và React" không? Tại sao nó xảy ra?
VB_

Bộ định tuyến React thường được sử dụng để xử lý các 'đường dẫn' khác nhau trong trình duyệt. Có hai cách điển hình để làm điều này: đường dẫn băm kiểu cũ và API lịch sử mới hơn. Làm mới trình duyệt sẽ thực hiện một yêu cầu máy chủ, sẽ bỏ qua mã bộ định tuyến phản ứng phía máy khách của bạn. Bạn sẽ cần xử lý đường dẫn trên máy chủ (nhưng chỉ khi bạn đang sử dụng API lịch sử). Bạn có thể sử dụng bộ định tuyến phản ứng cho việc này, nhưng bạn sẽ cần phải làm một cái gì đó tương tự như những gì tôi đã mô tả ở trên.
Todd

hiểu rồi. Nhưng làm thế nào để được nếu máy chủ sử dụng ngôn ngữ không phải là JS (giả sử Java)?
VB_

2
Xin lỗi, bạn có nghĩa là bạn yêu cầu một máy chủ cấp tốc để hiển thị tuyến đường "không root"? Trước tiên tôi rất ngạc nhiên khi định nghĩa của đẳng cấu không bao gồm tìm nạp dữ liệu trong khái niệm của nó (mọi thứ rất phức tạp nếu bạn muốn hiển thị chế độ xem với máy chủ dữ liệu, mặc dù đó là một nhu cầu SEO rõ ràng - và yêu cầu đẳng cấu). Bây giờ tôi giống như "phản ứng WTF", nghiêm túc khắc phục tôi nếu tôi sai, liệu ember / angular / xương sống có yêu cầu một thứ máy chủ để hiển thị tuyến đường không? Tôi thực sự không hiểu yêu cầu cồng kềnh này để sử dụng các tuyến đường
Ben

1
Điều đó có nghĩa là làm mới trong bộ định tuyến phản ứng không hoạt động nếu ứng dụng phản ứng của tôi không phải là đẳng cấu?
Matt

28

Trong index.html của bạn head, hãy thêm vào như sau:

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

Sau đó, khi chạy với máy chủ webpack dev sử dụng lệnh này.

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

--history-api-fallback là phần quan trọng


Điều này đã làm việc tuyệt vời! Bất kỳ liên kết để đọc thêm một số về cách bạn có / tìm thấy giải pháp đó?
justDan

1
Xin lỗi anh bạn. Tìm thấy nó thông qua các kỹ thuật thử và sai.
Efe Ariaroo

Điều đáng nói là nếu bạn đang sử dụng một cơ sở /thì điều đó HashRoutersẽ không hoạt động (nếu bạn đang sử dụng định tuyến băm)
Robbie Averill

Thẻ <base href = "/"> đã làm điều đó cho tôi. Cám ơn vì cái này. Máy chủ phát triển Webpack tiếp tục cố gắng lấy gói từ đường dẫn / <bundle> và đã thất bại.
Malisbad

27

Tôi đã sử dụng ứng dụng tạo phản ứng để tạo một trang web ngay bây giờ và có cùng một vấn đề được trình bày ở đây. Tôi sử dụng BrowserRoutingtừ react-router-domgói. Tôi đang chạy trên máy chủ Nginx và điều đã giải quyết nó cho tôi là thêm phần sau vào/etc/nginx/yourconfig.conf

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

Điều này tương ứng với việc thêm phần sau vào .htaccesstrong trường hợp bạn đang chạy Appache

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

Đây dường như cũng là giải pháp được đề xuất bởi chính Facebook và có thể tìm thấy ở đây


1
Wow, một giải pháp đơn giản cho nginx; hoạt động như một sự quyến rũ, như một người dùng nginx mới. Chỉ cần sao chép-dán và tốt để đi. +1 để liên kết đến tài liệu fb chính thức. Con đường để đi.
dùng3773048

Đối với bản ghi: Tôi đang sử dụng Sơ đồ AWS với nginx và Ứng dụng góc. Những công việc này.
Diego Sarmiento

bạn cứu tôi tôi đã cố gắng khắc phục vấn đề của tôi từ hôm qua, tôi mệt mỏi với một vài giải pháp nhưng tôi đã thất bại. cuối cùng bạn đã giúp tôi giải quyết vấn đề bộ định tuyến này. ah cảm ơn rất nhiều anh em
Sharifur Robin

Có bất cứ điều gì khác nhau cần thiết cho "phản ứng": "^ 16.8.6", "Reac-router": "^ 5.0.1" không? Tôi đã thử các giải pháp này (cả nginx và apache) và chúng không hoạt động.
Đánh dấu A. Tagliaferro

Vì Facebook đã không thay đổi tài liệu của mình về vấn đề này, tôi chỉ có thể giả sử quy trình này giống nhau. Tôi đã không thử nó trong một thời gian.
Aidin

17

Điều này có thể giải quyết vấn đề của bạn

Tôi cũng gặp phải vấn đề tương tự trong ứng dụng ReactJS trong chế độ Sản xuất. Đây là 2 giải pháp cho vấn đề.

1.Thay đổi lịch sử định tuyến thành "hashHistory" thay vì browserHistory thay cho

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

Bây giờ xây dựng ứng dụng bằng lệnh

sudo npm run build

Sau đó đặt thư mục xây dựng vào thư mục var / www / của bạn, Bây giờ ứng dụng đang hoạt động tốt với việc thêm thẻ # vào mỗi và mọi url. giống

localhost / # / home localhost / # / aboutus

Giải pháp 2: Không có thẻ # bằng browserHistory,

Đặt lịch sử của bạn = {browserHistory} trong Bộ định tuyến của bạn, Bây giờ hãy xây dựng nó bằng cách sử dụng sudo npm run build.

Bạn cần tạo tệp "conf" để giải quyết trang 404 không tìm thấy, tệp conf sẽ như thế này.

mở loại thiết bị đầu cuối của bạn các lệnh dưới đây

cd / etc / apache2 / site-ls nano sample.conf Thêm nội dung bên dưới vào đó.

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

Bây giờ bạn cần kích hoạt tệp sample.conf bằng cách sử dụng lệnh sau

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

sau đó nó sẽ yêu cầu bạn tải lại máy chủ apache, sử dụng dịch vụ sudo apache2 tải lại hoặc khởi động lại

sau đó mở thư mục localhost / build của bạn và thêm tệp .htaccess với nội dung bên dưới.

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

Bây giờ ứng dụng đang hoạt động bình thường.

Lưu ý: thay đổi ip 0.0.0.0 thành địa chỉ IP cục bộ của bạn.

Nếu có bất kỳ nghi ngờ nào về việc này, vui lòng đưa ra nhận xét.

Tôi hy vọng nó hữu ích cho người khác.


Giải pháp đầu tiên sẽ hoạt động cho "react-router-dom": "^5.1.2"?, Tôi đang sử dụng<BrowserRouter>
151291

16

Nếu bạn đang lưu trữ một ứng dụng phản ứng thông qua AWS Static S3 Hosting & CloudFront

Vấn đề này do CloudFront tự phản hồi với thông báo Từ chối truy cập 403 vì nó dự kiến ​​/ một số / khác / đường dẫn tồn tại trong thư mục S3 của tôi, nhưng đường dẫn đó chỉ tồn tại bên trong định tuyến của React với bộ định tuyến phản ứng.

Giải pháp là thiết lập quy tắc Trang lỗi phân phối. Chuyển đến cài đặt CloudFront và chọn phân phối của bạn. Tiếp theo, đi đến tab "Trang lỗi". Nhấp vào "Tạo phản hồi lỗi tùy chỉnh" và thêm mục nhập cho 403 vì đó là mã trạng thái lỗi chúng tôi nhận được. Đặt Đường dẫn trang phản hồi thành /index.html và mã trạng thái thành 200. Kết quả cuối cùng làm tôi ngạc nhiên với sự đơn giản của nó. Trang chỉ mục được cung cấp, nhưng URL được bảo toàn trong trình duyệt, do đó, khi ứng dụng phản ứng tải, nó sẽ phát hiện đường dẫn URL và điều hướng đến tuyến đường mong muốn.

Lỗi trang 403 Quy tắc


1
Đây chính xác là những gì tôi cần. Cảm ơn bạn.
Jonathan

Vì vậy, tất cả các url của bạn hoạt động, nhưng trả lại mã trạng thái 403? Nó không đúng. Mã trạng thái dự kiến ​​sẽ nằm trong phạm vi 2xx.
Stijn de Witt

@StijndeWitt Tôi không chắc bạn hiểu chính xác. CloudFront sẽ xử lý mọi thứ - khách hàng sẽ không thấy bất kỳ mã trạng thái 403 nào. Việc định tuyến lại xảy ra phía máy chủ, kết xuất trang chỉ mục, duy trì url và cung cấp tuyến chính xác.
th3morg

@ th3morg À đúng rồi. Tôi đã bỏ lỡ rằng nó cũng cho phép bạn điền mã trạng thái phản hồi là 200. Vì vậy, về cơ bản, bạn đang ánh xạ trạng thái 403 sang trạng thái 200 ... Có vẻ tốt ... ngoại trừ có thể nếu bạn nhận được 403 do một số lý do khác bạn sẽ không thể nhìn thấy nó vì điều này.
Stijn de Witt

1
cảm ơn vì điều này @ th3morg. Liệu thiết lập này cũng hoạt động cho các đường dẫn đa cấp? Nó hoạt động rất tốt cho tôi nếu bất kỳ đường dẫn nào ở cấp gốc, như tên miền / đăng ký, tên miền / đăng nhập, tên miền / <documentId>, nhưng nó không hoạt động cho các đường dẫn đa cấp, như tên miền / tài liệu / <documentId>.
Pargles

16

Webpack Dev Server có một tùy chọn để kích hoạt điều này. Mở package.jsonvà thêm --history-api-fallback. Giải pháp này đã làm việc cho tôi.

Reac-router-guide


3
Nó ổn với webpack-dev-servernhưng làm cách nào để sửa lỗi này cho bản dựng sản xuất?
Hussain

12

Nếu bạn đang lưu trữ ứng dụng phản ứng của mình trên IIS, chỉ cần thêm tệp web.config có chứa:

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

Điều này sẽ yêu cầu máy chủ IIS trả lại trang chính cho máy khách thay vì lỗi 404 và không cần sử dụng lịch sử băm.


cảm ơn nhé người anh em!!!! đó là công việc!
Thanh Bảo

12

Thêm cái này vào webpack.config.js:

devServer: {
    historyApiFallback: true
}

Điều đó thật tuyệt vời cho nhà phát triển, nhưng không giúp ích gì cho việc xây dựng sản xuất.
KFunk

11

Ngăn xếp sản xuất: React, React Router v4, BrowsewerRouter, Express, Nginx

1) Trình duyệt người dùngRouter cho các url đẹp

// app.js

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

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

2) Thêm index.html vào tất cả các yêu cầu chưa biết bằng cách sử dụng /*

// 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) gói webpack với webpack -p

4) chạy nodemon server.jshoặcnode server.js

EDIT: Bạn có thể muốn để nginx xử lý việc này trong khối máy chủ và bỏ qua bước 2:

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

nhận được đường dẫn không xác định
Goutham

@Goutham Ở đầu tệp server.js của bạn, hãy thêm import path from 'pathhoặcconst path = require('path')
Isaac Pak

bước 2 (bắt tất cả với /*) vừa lưu lại ngày của tôi. Cảm ơn bạn! :)
Atlas7

Điều này hoạt động, đối với những người sử dụng redux và quan tâm đến bộ định tuyến được kết nối, hãy xem ví dụ này: github.com/supasate/connected-react-router/tree/master/examples/
trộm

10

Nếu bạn đang sử dụng Tạo ứng dụng React:

Có một bước đi tuyệt vời mặc dù vấn đề này với các giải pháp cho nhiều nền tảng lưu trữ lớn mà bạn có thể tìm thấy TẠI ĐÂY trên trang Tạo ứng dụng Phản ứng. Ví dụ: tôi sử dụng React Router v4 và Netlify cho mã frontend của mình. Tất cả chỉ cần thêm 1 tệp vào thư mục công cộng của tôi ("_redirects") và một dòng mã trong tệp đó:

/*  /index.html  200

Bây giờ trang web của tôi hiển thị chính xác các đường dẫn như mysite.com/pricing khi được nhập vào trình duyệt hoặc khi ai đó nhấn refresh.


7

Hãy thử thêm tệp ".htaccess" vào thư mục chung với mã bên dưới.

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

RewriteRule ^ /index.html [L]  

Cảm ơn, đây là những gì làm việc cho tôi trên Fedora 28 với apache. Không có quy tắc viết lại nào ở trên cũng như các quy tắc trên trang CRA làm việc cho tôi. Tôi đã thêm chúng vào thiết lập máy chủ ảo thay vì trong một tệp .htaccess riêng biệt.
boerre

6

Nếu bạn có dự phòng cho index.html của mình, hãy đảm bảo rằng trong tệp index.html của bạn, bạn có cái này:

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

Điều này có thể khác nhau từ dự án để dự án.


2
Thêm phần này vào html của bạn head: <base href = "/"
Efe Ariaroo

4

Nếu bạn đang sử dụng firebase, tất cả những gì bạn phải làm là đảm bảo rằng bạn đã có một thuộc tính ghi lại trong tệp firebase.json trong thư mục gốc của ứng dụng (trong phần lưu trữ).

Ví dụ:

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

Hy vọng điều này sẽ giúp người khác tiết kiệm được sự thất vọng và lãng phí thời gian.

Chúc mừng mã hóa ...

Đọc thêm về chủ đề:

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

Firebase CLI: "Định cấu hình dưới dạng một ứng dụng một trang (viết lại tất cả các url thành /index.html)"


Bạn là một huyền thoại
Perniferous

4

Tôi đã tìm thấy giải pháp cho SPA của mình với bộ định tuyến phản ứng (Apache). Chỉ cần thêm .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>

nguồn: https://gist.github.com/alexsasharegan/173878f9d67055bfef63449fa7136042


3

Tôi chưa sử dụng kết xuất phía máy chủ nhưng tôi gặp vấn đề tương tự như OP nơi Link dường như hoạt động tốt hầu hết thời gian nhưng không thành công khi tôi có một tham số. Tôi sẽ ghi lại giải pháp của mình ở đây để xem nó có giúp được ai không.

Jsx chính của tôi có chứa điều này:

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

Điều này hoạt động tốt cho liên kết khớp đầu tiên nhưng khi: id thay đổi trong <Link> biểu thức được lồng trên trang chi tiết của mô hình đó, url thay đổi trong thanh trình duyệt nhưng nội dung của trang ban đầu không thay đổi để phản ánh mô hình được liên kết.

Vấn đề là tôi đã sử dụng props.params.idđể đặt mô hình componentDidMount. Thành phần này chỉ được gắn một lần nên điều này có nghĩa là mô hình đầu tiên là mô hình dính trên trang và các Liên kết tiếp theo thay đổi đạo cụ nhưng vẫn giữ nguyên trang không thay đổi.

Đặt mô hình ở trạng thái thành phần ở cả hai componentDidMountvà trong componentWillReceiveProps(nơi dựa trên các đạo cụ tiếp theo) sẽ giải quyết vấn đề và nội dung trang thay đổi để phản ánh mô hình mong muốn.


1
Có thể tốt hơn để sử dụng hàm tạo thành phần (cũng có quyền truy cập props) iso componentDidMountnếu bạn muốn thử kết xuất phía máy chủ. Bởi vì componentDidMountchỉ được gọi trong trình duyệt. Mục đích của nó là làm mọi thứ với DOM, chẳng hạn như gắn trình lắng nghe sự kiện vào bodyvv mà bạn không thể làm render.
Stijn de Witt

3

Chủ đề này hơi cũ và đã được giải quyết nhưng tôi muốn đề xuất cho bạn một giải pháp đơn giản, rõ ràng và tốt hơn. Nó hoạt động nếu bạn sử dụng máy chủ web.

Mỗi máy chủ web có khả năng chuyển hướng người dùng đến trang lỗi trong trường hợp http 404. Để giải quyết vấn đề này, bạn cần chuyển hướng người dùng đến trang chỉ mục.

Nếu bạn sử dụng máy chủ cơ sở Java (tomcat hoặc bất kỳ máy chủ ứng dụng java nào), giải pháp có thể là như sau:

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>

Thí dụ:

  • NHẬN http://example.com/about
  • Máy chủ web ném http 404 vì trang này không tồn tại ở phía máy chủ
  • cấu hình trang lỗi báo cho máy chủ gửi lại trang index.jsp cho người dùng
  • sau đó, JS sẽ thực hiện phần còn lại của công việc ở phía clien vì url ở phía máy khách vẫn là http://example.com/about .

Thế là xong, không cần thêm phép thuật :)


Nó thật là tuyệt vời! Tôi đang sử dụng máy chủ Wildfly 10.1 và thực hiện cập nhật này cho tệp web.xml của mình, ngoại trừ tôi đã đặt vị trí thành '/'. Điều này là do trong mã phản ứng của tôi, tôi đã sử dụng lịch sử trình duyệt như thế này:const browserHistory = useRouterHistory(createHistory)({ basename: '/<appname>' });
Chuck L

1
Bạn có chắc chắn rằng điều này không ảnh hưởng đến SEO? Bạn đang đưa ra trạng thái 404 cho các trang thực sự tồn tại. Người dùng có thể không bao giờ nhận ra điều này, nhưng các bot thực sự chú ý, thực tế là rất nhiều, họ sẽ không cạo trang của bạn.
subharb

3

Nếu bạn đang sử dụng Express hoặc một số khung công tác khác trong phần phụ trợ, bạn có thể thêm cấu hình tương tự như bên dưới và kiểm tra đường dẫn công khai Webpack trong cấu hình, nó sẽ hoạt động tốt ngay cả khi tải lại nếu bạn đang sử dụng BrowserRouter

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

đây là giải pháp đơn giản nhất lưu ý tuyến đường này nên đi sau bất kỳ tuyến đường nào khác vì nó bắt tất cả
dcsan

3

Khắc phục lỗi "không thể NHẬN / URL" khi làm mới hoặc gọi URL trực tiếp.

Định cấu hình webpack.config.js của bạn để mong đợi liên kết đã cho các tuyến đường như thế này.

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

2

Khi tôi đang sử dụng .Net Core MVC, một cái gì đó như thế này đã giúp tôi:

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

Về cơ bản ở phía MVC, tất cả các tuyến không khớp sẽ rơi vào Home/Indexnhư được chỉ định trong startup.cs. Bên trong Indexcó thể lấy url yêu cầu ban đầu và chuyển nó bất cứ nơi nào cần thiết.

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

Nếu api web được tách ra khỏi ứng dụng, bạn sẽ xử lý việc này như thế nào?
dayanrr91

@ dayanrr91 nếu dự án của bạn có web api, bạn sẽ không cần định tuyến phía máy chủ. Và bộ định tuyến phản ứng của bạn tôi tin rằng nên đọc url và thực hiện định tuyến thích hợp. Không có gì nên chặn nó
Elnoor

Nhận xét của bạn rất được đánh giá cao, nhưng sau đó tôi có một câu hỏi, tôi mới thêm HashRouter, nhưng bây giờ khi tôi nhập bất kỳ URL nào theo cách thủ công, nó sẽ chuyển hướng đến thành phần nhà của tôi thay vì chuyển hướng đến nhà của tôi và sau đó đến thành phần mà tôi đang cố gắng nhận được vào, có bất kỳ cách giải quyết cho điều đó?
dayanrr91

@ dayanrr91 thực sự không có ý tưởng nào, chưa thử hashrouter bao giờ nhưng tôi nghĩ nên làm gì đó với mã của bạn. Cách thức hoạt động của hashrouter tương tự như browserrouter. Ngoài ra tôi vừa thử nghiệm ở đây trong hộp cát này, nó hoạt động tốt với các mã và hộp.io / s / 25okp1mny , kiểm tra url 25okp1mny.codesandbox.io/#/roster/5
Elnoor

2

Nếu bạn đang lưu trữ trong IIS; Thêm cái này vào webconfig đã giải quyết vấn đề của tôi

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

Bạn có thể tạo cấu hình tương tự cho bất kỳ máy chủ nào khác


1

Trong trường hợp, bất cứ ai ở đây đang tìm kiếm giải pháp trên React JS SPA với Laravel. Câu trả lời được chấp nhận là lời giải thích tốt nhất về lý do tại sao những vấn đề như vậy xảy ra. Như đã giải thích, bạn phải cấu hình cả phía máy khách và phía máy chủ. Trong mẫu lưỡi của bạn, bao gồm tệp được đóng gói js, đảm bảo sử dụng URL facadenhư thế này

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

Trong các tuyến đường của bạn, đảm bảo thêm phần này vào điểm cuối chính nơi có mẫu lưỡi cắt. Ví dụ,

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

Trên đây là điểm cuối chính cho mẫu lưỡi cắt. Bây giờ thêm một tuyến tùy chọn quá,

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

Vấn đề xảy ra là đầu tiên mẫu lưỡi được tải, sau đó là bộ định tuyến phản ứng. Vì vậy, khi bạn đang tải '/setting-alerts', nó sẽ tải html và js. Nhưng khi bạn tải '/setting-alerts/about', đầu tiên nó tải ở phía máy chủ. Vì ở phía máy chủ, không có gì ở vị trí này, nó trả về không tìm thấy. Khi bạn có bộ định tuyến tùy chọn đó, nó sẽ tải cùng trang đó và bộ định tuyến phản ứng cũng được tải, sau đó bộ tải phản ứng quyết định thành phần nào sẽ hiển thị. Hi vọng điêu nay co ich.


Có thể tải một URI chính xác đến máy chủ sau đó máy chủ thực hiện chuyển hướng đến React không? Giống như ví dụ, khi tôi tải /user/{userID}, tôi chỉ cần trả về /userchế độ xem HTML phổ quát , mang ID và gọi nó bằng AJAX hoặc axios. Có thể làm điều đó? Họ có thân thiện với SEO không?
Ryuujo

1

Đối với những người đang sử dụng IIS 10, đây là những gì bạn nên làm để thực hiện đúng. Hãy chắc chắn rằng bạn đang sử dụng browserHistory với điều này. Để tham khảo tôi sẽ đưa ra mã cho định tuyến, nhưng đây không phải là vấn đề quan trọng, điều quan trọng là bước tiếp theo sau mã thành phần dưới đây:

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

Vì vấn đề là IIS nhận được yêu cầu từ trình duyệt máy khách, nên nó sẽ diễn giải URL như thể nó đang yêu cầu một trang, sau đó trả về một trang 404 vì không có trang nào khả dụng. Làm như sau:

  1. Mở IIS
  2. Mở rộng Máy chủ, sau đó mở Thư mục Trang web
  3. Nhấp vào trang web / ứng dụng
  4. Chuyển đến trang lỗi
  5. Mở mục trạng thái lỗi 404 trong danh sách
  6. Thay vì tùy chọn "Chèn nội dung từ tệp tĩnh vào phản hồi lỗi", hãy đổi nó thành "Thực thi URL trên trang web này" và thêm giá trị gạch chéo "/" vào URL.

Và bây giờ nó sẽ hoạt động tốt.

nhập mô tả hình ảnh ở đây nhập mô tả hình ảnh ở đây

Tôi hy vọng nó sẽ giúp. :-)


1

Tôi đang sử dụng WebPack, tôi gặp vấn đề tương tự Solution => Trong tệp server.js của bạn

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

Tại sao ứng dụng của tôi không hiển thị sau khi làm mới?


Điều này đã làm điều đó cho tôi! Ban đầu tôi có res.sendFile (path.JOIN (publicPath, "index.html")); Tôi đã thay đổi "tham gia" thành "đã giải quyết" như trong ví dụ trên thành: res.sendFile (path.resolve ("./ dist", "index.html")); Tôi cũng đang chơi xung quanh với __dirname nhưng không thể hiểu nó hoặc làm cho nó hoạt động nên tôi đã sao chép thủ công trong "./dist" vì đây là nơi index.html của tôi được phục vụ. Tôi cũng đã tuyên bố như vậy trước đó: app.use (express.static ("./ dist"));
logixplayer

1

Sử dụng cũng HashRoutercó hiệu quả với Redux , chỉ cần thay thế:

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

đến:

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

Tôi đã có cùng một vấn đề và giải pháp này đã làm việc cho chúng tôi ..

Lý lịch:

Chúng tôi đang lưu trữ nhiều ứng dụng trên cùng một máy chủ. Khi chúng tôi làm mới, máy chủ sẽ không hiểu nơi tìm chỉ mục của chúng tôi trong thư mục dist cho ứng dụng cụ thể đó. Liên kết trên sẽ đưa bạn đến những gì làm việc cho chúng tôi ... Hy vọng điều này sẽ giúp ích, vì chúng tôi đã dành khá nhiều giờ để tìm ra giải pháp cho nhu cầu của mình.

Chúng tôi đang sử dụng:

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 của tôi

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

index.js của tôi

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

app.js của tôi

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

Tôi thích cách xử lý này. Hãy thử thêm: yourSPAPageRoute / * ở phía máy chủ để thoát khỏi vấn đề này.

Tôi đã thực hiện theo cách tiếp cận này vì ngay cả API Lịch sử HTML5 gốc cũng không hỗ trợ chuyển hướng chính xác khi làm mới trang (Theo như tôi biết).

Lưu ý: Câu trả lời được chọn đã giải quyết vấn đề này nhưng tôi đang cố gắng cụ thể hơn.

Tuyến cao tốc

Kiểm tra - API lịch sử Đã thử nghiệm và chỉ muốn chia sẻ điều này.

Hy vọng nó giúp.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.