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

标签 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>
    );
  }
}
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,它有一个带获取功能的构造函数。用不存在的路径替换示例 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. 充当网络服务器来托管静态文件(您的 React 应用程序)
  2. 提供 API 响应(您的 C# Controller )

您注意到的行为(提供 index.html 而不是针对丢失的页面返回 404)是 #1 的一部分。更改您的 React 路由代码并没有什么不同,因为它是服务器行为。 ASP.NET Core 将此称为“SPA 回退路由”。 This excellent blog post称之为“可配置静态”行为:

A web server can be configured to respond with an alternative file if the requested resource doesn’t actually exist on the disk. If a request for /bears comes in and the server has no bears file, the configuration can tell it to respond with an index.html file instead.

目标是让拥有“漂亮”的 URL 变得更容易。如果你的 React 单页应用描述了类似 /counter 的路由,但服务器上没有 counter.html,那么有人直接从书签导航到 /counter 或者刷新浏览器将看到 404 错误消息。通过将服务器(在本例中为 ASP.NET Core)配置为提供 index.html 而不是 404,React 应用将被加载并可以正确响应 URL 中的路径。

如果您注释掉 Startup 类中的 app.UseSpaStaticFiles() 行,您的服务器应该开始返回真正的 404。但这给前端路由留下了上述问题。

这是我在我的项目中用于服务 index.html 的片段except 当请求路径以 /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"));
        });
    });

关于javascript - 带有 React 模板的 ASP.NET Core 返回 index.html,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57773828/

相关文章:

javascript - 在 React.js 中执行去抖动

javascript - 获取所有属性名称

负责返回和更新数据的 JavaScript 函数

javascript - 多个特殊字符替换优化

c# - Foreach 循环创建 100 个按钮,同时绘制所有按钮以防止闪烁

c# - 如何解析具有多个小数点的字符串

c# - 复制委托(delegate)

javascript - 在 JSX 中运行时选择 React 组件的类型

javascript - 如何在 Sencha Touch 中向模型添加自定义验证规则

reactjs - 如何从外部 React 组件获取 Auth0 token ?