ASP.NET 核心与 React 模板 returns index.html
ASP.NET Core with React template returns index.html
我正在学习使用 .NET Core 和 React 进行全栈 Web 开发,因此我在 Visual Studio 2019 年使用 React 模板创建了一个 ASP.NET 核心 Web 应用程序项目。
有时我注意到,如果我请求一个不存在的 URL,我不会像我预期的那样收到错误或 404 页面,而是收到 index.html 作为响应。
我希望我的后端 return 在调用不存在的 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 发送请求也是 returns 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?}");
});
不会改变程序的行为。但是,如果我完全删除此代码,前端将加载,但获取函数不会 return 数据,它再次 return 是 index.html。我尝试更改模板,但在我看来,它对程序行为没有影响。
我真的很困惑,我是不是搞错了什么?当请求不存在的 URL 时,return 错误或 404 页面难道不是预期的默认行为吗?我在网上也找不到很多。
我找到了这个答案,但它没有给出任何参考或解释为什么它是默认行为。
我尝试使用此答案中的代码,但它阻止了所有不是 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 模板创建了一个同时做两件事的项目:
- 充当 Web 服务器来托管静态文件(您的 React 应用程序)
- 提供 API 个响应(您的 C# 控制器)
您注意到的行为(服务 index.html 而不是针对丢失的页面返回 404)是 #1 的一部分。更改您的 React 路由代码并没有什么不同,因为它是服务器行为。 ASP.NET 核心称之为 "SPA fallback route"。 This excellent blog post 称之为 "configurable static" 行为:
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.
目标是让 "pretty" URL 更容易。如果你的 React 单页应用程序描述了一个像 /counter
这样的路由,但服务器上没有 counter.html,那么有人从书签直接导航到 /counter
或刷新他们的浏览器会看到404 错误消息。通过配置服务器(在本例中为 ASP.NET Core)服务于 index.html 而不是 404,React 应用程序将被加载并且可以正确响应 URL.[=18 中的路径=]
如果您注释掉 Startup
class 中的 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"));
});
});
我正在学习使用 .NET Core 和 React 进行全栈 Web 开发,因此我在 Visual Studio 2019 年使用 React 模板创建了一个 ASP.NET 核心 Web 应用程序项目。
有时我注意到,如果我请求一个不存在的 URL,我不会像我预期的那样收到错误或 404 页面,而是收到 index.html 作为响应。
我希望我的后端 return 在调用不存在的 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 发送请求也是 returns 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?}");
});
不会改变程序的行为。但是,如果我完全删除此代码,前端将加载,但获取函数不会 return 数据,它再次 return 是 index.html。我尝试更改模板,但在我看来,它对程序行为没有影响。
我真的很困惑,我是不是搞错了什么?当请求不存在的 URL 时,return 错误或 404 页面难道不是预期的默认行为吗?我在网上也找不到很多。
我找到了这个答案,但它没有给出任何参考或解释为什么它是默认行为。
我尝试使用此答案中的代码,但它阻止了所有不是 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 模板创建了一个同时做两件事的项目:
- 充当 Web 服务器来托管静态文件(您的 React 应用程序)
- 提供 API 个响应(您的 C# 控制器)
您注意到的行为(服务 index.html 而不是针对丢失的页面返回 404)是 #1 的一部分。更改您的 React 路由代码并没有什么不同,因为它是服务器行为。 ASP.NET 核心称之为 "SPA fallback route"。 This excellent blog post 称之为 "configurable static" 行为:
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.
目标是让 "pretty" URL 更容易。如果你的 React 单页应用程序描述了一个像 /counter
这样的路由,但服务器上没有 counter.html,那么有人从书签直接导航到 /counter
或刷新他们的浏览器会看到404 错误消息。通过配置服务器(在本例中为 ASP.NET Core)服务于 index.html 而不是 404,React 应用程序将被加载并且可以正确响应 URL.[=18 中的路径=]
如果您注释掉 Startup
class 中的 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"));
});
});