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

Ale*_*ski 14 javascript c# reactjs asp.net-core visual-studio-2019

我正在学习使用 .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>
    );
  }
}
Run Code Online (Sandbox Code Playgroud)
import React from 'react';

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

但我认为这不是问题的真正解决方案,因为我后来发现通过 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 });
    });
}
Run Code Online (Sandbox Code Playgroud)

所以,我认为问题出在 .NET Core 后端。我转到启动文件并尝试在那里修复此行为,我注意到从这段代码的括号中删除所有内容时:

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

不会改变程序的行为。但是,如果我完全删除此代码,前端将加载,但 fetch 函数不返回数据,它再次返回 index.html。我试图更改模板,但在我看来,它对程序行为没有影响。

我真的很困惑,我是不是搞错了什么?请求不存在的 URL 时返回错误或 404 页面不是预期的默认行为吗?我在互联网上也找不到太多。

/sf/answers/3758126571/

我找到了这个答案,但它没有给出任何关于为什么它是默认行为的参考或解释。

/sf/answers/3091530991/

我尝试使用此答案中的代码,但它会阻止所有不是 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");
    }
  });
});
Run Code Online (Sandbox Code Playgroud)

Nat*_*ini 12

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 中的路径。

如果您app.UseSpaStaticFiles()Startup类中注释掉该行,您的服务器应该开始返回真正的 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"));
        });
    });
Run Code Online (Sandbox Code Playgroud)