簡體   English   中英

帶有 React 模板的 ASP.NET Core 返回 index.html

[英]ASP.NET Core with React template returns index.html

我正在學習使用 .NET Core 和 React 進行全棧 Web 開發,因此我在 Visual Studio 2019 中使用 React 模板創建了一個 ASP.NET Core Web 應用程序項目。

在某些時候,我注意到如果我請求一個不存在的 URL,我不會像預期的那樣收到錯誤或 404 頁面,而是收到 index.html 作為響應。

我希望我的后端在調用不存在的 URL 時返回 404 狀態代碼。

我試圖通過在 App.js 中的 Route 標簽周圍添加一個 React Switch 標簽來解決這個問題,並添加了一個在請求的 URL 與定義的路由不匹配時顯示的組件:

import React, { Component } from 'react';
import { Route, Switch } from 'react-router';
import { Layout } from './components/Layout';
import { Home } from './components/Home';
import { FetchData } from './components/FetchData';
import { Counter } from './components/Counter';
import NoMatch from './components/NoMatch'; // <-- Added this

export default class App extends Component {
  static displayName = App.name;

  render () {
    return (
      <Layout>
        <Switch> // <-- Added this
          <Route exact path='/' component={Home} />
          <Route path='/counter' component={Counter} />
          <Route path='/fetch-data' component={FetchData} />
          <Route component={NoMatch} /> // <-- Added this
        </Switch> // <-- Added this
      </Layout>
    );
  }
}
import React from 'react';

export default function NoMatch() {
  return (
    <div>
      <h1>Error</h1>
      <h2>404</h2>
      <p>Page was not found</p>
    </div>
  );
}

但我認為這不是問題的真正解決方案,因為我后來發現通過 fetch 函數向不存在的 API 發送請求也會返回 index.html 作為響應。 該項目有一個示例組件 FetchData,它有一個帶有 fetch 函數的構造函數。 用不存在的路徑替換示例 URL 會重現以下行為:

constructor (props) {
  super(props);
  this.state = { forecasts: [], loading: true };

  fetch('api/nonexistingpath') // <-- Changed this URL
    .then(response => response.json())
    .then(data => {
      this.setState({ forecasts: data, loading: false });
    });
}

所以,我認為問題出在 .NET Core 后端。 我轉到啟動文件並嘗試在那里修復此行為,我注意到從這段代碼的括號中刪除所有內容時:

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

不會改變程序的行為。 但是,如果我完全刪除此代碼,前端將加載,但 fetch 函數不返回數據,它再次返回 index.html。 我試圖更改模板,但在我看來,它對程序行為沒有影響。

我真的很困惑,我是不是搞錯了什么? 請求不存在的 URL 時返回錯誤或 404 頁面不是預期的默認行為嗎? 我在互聯網上也找不到太多。

https://stackoverflow.com/a/53687522/10951989

我找到了這個答案,但它沒有給出任何關於為什么它是默認行為的參考或解釋。

https://stackoverflow.com/a/44164728/10951989

我嘗試使用此答案中的代碼,但它會阻止所有不是 API 調用的內容。 有人可以幫助我嗎?

先感謝您!

更新 #1

好的,經過長時間的嘗試,我似乎找到了適合我的解決方案:

app.MapWhen(x => x.Request.Path.Value.StartsWith("/api"), builder =>
{
  app.UseMvc();
});

app.MapWhen(x => !x.Request.Path.Value.StartsWith("/api"), builder =>
{
  app.UseSpa(spa =>
  {
    spa.Options.SourcePath = "ClientApp";

    if (env.IsDevelopment())
    {
      spa.UseReactDevelopmentServer(npmScript: "start");
    }
  });
});

ASP.NET Core + React 模板創建了一個同時做兩件事的項目:

  1. 充當 Web 服務器來托管靜態文件(您的 React 應用程序)
  2. 提供 API 響應(您的 C# 控制器)

您注意到的行為(提供 index.html 而不是為丟失的頁面返回 404)是 #1 的一部分。 更改您的 React 路由代碼並沒有什么不同,因為它是服務器行為。 ASP.NET Core 將此稱為“SPA 回退路線”。 這篇優秀的博客文章稱其為“可配置的靜態”行為:

如果請求的資源實際上不存在於磁盤上,則可以將 Web 服務器配置為使用替代文件進行響應。 如果請求 /bears 並且服務器沒有 bears 文件,配置可以告訴它用 index.html 文件來響應。

目標是更容易擁有“漂亮”的 URL。 如果你的 React 單頁應用程序描述了一個類似於/counter的路由,但服務器上沒有 counter.html,那么有人從書簽直接導航到/counter或刷新瀏覽器將看到 404 錯誤消息。 通過將服務器(在本例中為 ASP.NET Core)配置為提供 index.html 而不是 404,React 應用程序將被加載並可以正確響應 URL 中的路徑。

如果您注釋掉Startup類中的app.UseSpaStaticFiles()行,您的服務器應該開始返回真正的 404。 但這留下了前端路由的上述問題。

這是我在我的項目中使用的一個片段來提供 index.html除非請求路徑以/api開頭:

    app.UseMvc();

    app.MapWhen(x => !x.Request.Path.Value.StartsWith("/api"), builder =>
    {
        app.Run(async (context) =>
        {
            context.Response.ContentType = "text/html";
            context.Response.Headers[HeaderNames.CacheControl] = "no-store, no-cache, must-revalidate";
            await context.Response.SendFileAsync(Path.Combine(env.WebRootPath, "index.html"));
        });
    });

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM