.NET Core、Angular2、NancyFX - 404 在浏览器中发生变化 URL
.NET Core, Angular2, NancyFX - 404 changing URL in browser
使用 .NET Core 静态文件为应用程序提供服务时,我无法在浏览器中更改 URL。这样做时,我得到了
404 - Not Found
南希错误页面。
唯一有效的 URL 是基础 URL、localhost:5000。将 URL 更改为 localhost:5000/reservations 会得到 404。不在基地时按 F5 URL 也会得到 404。
如果我使用 browsersync url、localhost:4200,一切正常,我可以更改 URL 并在没有 404 的情况下按 F5。这就是我在开发时所做的,但是不是在使用 IIS 部署到服务器上时。
运行 IIS Express中的应用程序
ng 构建(文件与 index.html 一起复制到 wwwroot)
启动 IIS Express
Startup.cs
public class Startup
{
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
env.ConfigureNLog("nlog.config");
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(IISDefaults.AuthenticationScheme);
services.AddMvc(config =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
config.Filters.Add(new AuthorizeFilter(policy));
});
services.AddMvc();
services.InjectServices();
services.AddOptions();
services.Configure<Endpoints>(Configuration.GetSection("Endpoints"));
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddSingleton<IConfiguration>(Configuration);
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.Use(async (context, next) =>
{
await next();
if (!context.Request.Path.Value.StartsWith("/api/"))
{
context.Request.Path = "/index.html";
await next();
}
});
app.UseDefaultFiles();
app.UseStaticFiles();
loggerFactory.AddNLog();
app.AddNLogWeb();
app.UseOwin(x => x.UseNancy(new NancyOptions
{
Bootstrapper = new Bootstrapper(app)
}));
}
}
Bootstrapper.cs
public class Bootstrapper : DefaultNancyBootstrapper
{
readonly IApplicationBuilder _app;
public Bootstrapper(IApplicationBuilder app)
{
_app = app;
}
protected override void ConfigureApplicationContainer(TinyIoCContainer container)
{
base.ConfigureApplicationContainer(container);
container.Register<IOptions<Endpoints>>(_app.ApplicationServices.GetService<IOptions<Endpoints>>());
container.Register<IReservationService>(_app.ApplicationServices.GetService<IReservationService>());
}
}
wwwroot
index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>XXX</title>
<base href="/">
<meta name="viewport" content="width=device-width,initial-scale=1">
<link rel="icon" type="image/x-icon" href="XXX">
<link href="styles.61cc257ef8131303860b.bundle.css" rel="stylesheet" />
</head>
<body>
<app-root></app-root>
<script type="text/javascript" src="inline.f68c652d205feae6e02a.bundle.js"></script>
<script type="text/javascript" src="polyfills.756a44edc7e0a68ce65c.bundle.js"></script>
<script type="text/javascript" src="vendor.940a3ce39a746f717f7b.bundle.js"></script>
<script type="text/javascript" src="main.d5f9dd82a3600822cae2.bundle.js"></script>
</body>
</html>
我知道处理来自服务器的静态内容存在一些问题,但我似乎无法弄清楚。
在 .NET Core 中托管 Angular 应用程序时,如何使用浏览器 URL 导航?
更新 1:
添加后:
PerformPassThrough = (context => context.Response.StatusCode == HttpStatusCode.NotFound)
404 错误消息消失了,但页面现在是空白的,除了控制台中的 404 之外没有任何错误消息..
IMO 你写的中间件应该在 app.UseDefaultFiles() 之后;和 app.UseStaticFiles();
而且您只处理 API 个请求。尝试稍微重写它以处理 404 错误并且不处理带有扩展的请求:
app.Use(async (context, next) =>
{
await next();
if (context.Response.StatusCode == 404
&& !Path.HasExtension(context.Request.Path.Value)
&& !context.Request.Path.Value.StartsWith("/api/"))
{
context.Request.Path = "/index.html";
await next();
}
});
您需要删除第一个 await next();
。那是将请求发送到管道中的 /reservations
,before 将 URL 重写为 index.html
。
当它到达 Nancy 时,它将查看它是否可以处理 /reservations
,但它不能,并呈现 404 页面。
- 已修改Startup.cs
- 为所有请求添加了 returns index.html 模块。
- 在 bootstrapper.cs 中配置的根路径。
Startup.cs
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
//For serving index.html on baseurl - this can we done in AppNancyModule aswell: Get("/", _ => View["index"]);
app.UseDefaultFiles();
app.UseStaticFiles();
loggerFactory.AddNLog();
app.AddNLogWeb();
app.UseOwin(x => x.UseNancy(new NancyOptions
{
Bootstrapper = new Bootstrapper(app, env)
}));
}
AppNancyModule
public class AppNancyModule : NancyModule
{
public AppNancyModule()
{
//Get("/", _ => View["index"]);
Get(@"^(.*)$", _ => View["index"]);
}
}
Bootstrapper.cs
public class AppRootPathProvider : IRootPathProvider
{
private readonly IHostingEnvironment _environment;
public AppRootPathProvider(IHostingEnvironment environment)
{
_environment = environment;
}
public string GetRootPath()
{
return _environment.WebRootPath;
}
}
public class Bootstrapper : DefaultNancyBootstrapper
{
readonly IApplicationBuilder _app;
protected override IRootPathProvider RootPathProvider { get; }
public Bootstrapper(IApplicationBuilder app, IHostingEnvironment environment)
{
RootPathProvider = new AppRootPathProvider(environment);
_app = app;
}
protected override void ConfigureApplicationContainer(TinyIoCContainer container)
{
base.ConfigureApplicationContainer(container);
container.Register<IOptions<Endpoints>>(_app.ApplicationServices.GetService<IOptions<Endpoints>>());
container.Register<IReservationService>(_app.ApplicationServices.GetService<IReservationService>());
}
}
使用 .NET Core 静态文件为应用程序提供服务时,我无法在浏览器中更改 URL。这样做时,我得到了
404 - Not Found
南希错误页面。
唯一有效的 URL 是基础 URL、localhost:5000。将 URL 更改为 localhost:5000/reservations 会得到 404。不在基地时按 F5 URL 也会得到 404。
如果我使用 browsersync url、localhost:4200,一切正常,我可以更改 URL 并在没有 404 的情况下按 F5。这就是我在开发时所做的,但是不是在使用 IIS 部署到服务器上时。
运行 IIS Express中的应用程序
ng 构建(文件与 index.html 一起复制到 wwwroot)
启动 IIS Express
Startup.cs
public class Startup
{
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
env.ConfigureNLog("nlog.config");
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(IISDefaults.AuthenticationScheme);
services.AddMvc(config =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
config.Filters.Add(new AuthorizeFilter(policy));
});
services.AddMvc();
services.InjectServices();
services.AddOptions();
services.Configure<Endpoints>(Configuration.GetSection("Endpoints"));
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddSingleton<IConfiguration>(Configuration);
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.Use(async (context, next) =>
{
await next();
if (!context.Request.Path.Value.StartsWith("/api/"))
{
context.Request.Path = "/index.html";
await next();
}
});
app.UseDefaultFiles();
app.UseStaticFiles();
loggerFactory.AddNLog();
app.AddNLogWeb();
app.UseOwin(x => x.UseNancy(new NancyOptions
{
Bootstrapper = new Bootstrapper(app)
}));
}
}
Bootstrapper.cs
public class Bootstrapper : DefaultNancyBootstrapper
{
readonly IApplicationBuilder _app;
public Bootstrapper(IApplicationBuilder app)
{
_app = app;
}
protected override void ConfigureApplicationContainer(TinyIoCContainer container)
{
base.ConfigureApplicationContainer(container);
container.Register<IOptions<Endpoints>>(_app.ApplicationServices.GetService<IOptions<Endpoints>>());
container.Register<IReservationService>(_app.ApplicationServices.GetService<IReservationService>());
}
}
wwwroot
index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>XXX</title>
<base href="/">
<meta name="viewport" content="width=device-width,initial-scale=1">
<link rel="icon" type="image/x-icon" href="XXX">
<link href="styles.61cc257ef8131303860b.bundle.css" rel="stylesheet" />
</head>
<body>
<app-root></app-root>
<script type="text/javascript" src="inline.f68c652d205feae6e02a.bundle.js"></script>
<script type="text/javascript" src="polyfills.756a44edc7e0a68ce65c.bundle.js"></script>
<script type="text/javascript" src="vendor.940a3ce39a746f717f7b.bundle.js"></script>
<script type="text/javascript" src="main.d5f9dd82a3600822cae2.bundle.js"></script>
</body>
</html>
我知道处理来自服务器的静态内容存在一些问题,但我似乎无法弄清楚。
在 .NET Core 中托管 Angular 应用程序时,如何使用浏览器 URL 导航?
更新 1:
添加后:
PerformPassThrough = (context => context.Response.StatusCode == HttpStatusCode.NotFound)
404 错误消息消失了,但页面现在是空白的,除了控制台中的 404 之外没有任何错误消息..
IMO 你写的中间件应该在 app.UseDefaultFiles() 之后;和 app.UseStaticFiles(); 而且您只处理 API 个请求。尝试稍微重写它以处理 404 错误并且不处理带有扩展的请求:
app.Use(async (context, next) =>
{
await next();
if (context.Response.StatusCode == 404
&& !Path.HasExtension(context.Request.Path.Value)
&& !context.Request.Path.Value.StartsWith("/api/"))
{
context.Request.Path = "/index.html";
await next();
}
});
您需要删除第一个 await next();
。那是将请求发送到管道中的 /reservations
,before 将 URL 重写为 index.html
。
当它到达 Nancy 时,它将查看它是否可以处理 /reservations
,但它不能,并呈现 404 页面。
- 已修改Startup.cs
- 为所有请求添加了 returns index.html 模块。
- 在 bootstrapper.cs 中配置的根路径。
Startup.cs
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
//For serving index.html on baseurl - this can we done in AppNancyModule aswell: Get("/", _ => View["index"]);
app.UseDefaultFiles();
app.UseStaticFiles();
loggerFactory.AddNLog();
app.AddNLogWeb();
app.UseOwin(x => x.UseNancy(new NancyOptions
{
Bootstrapper = new Bootstrapper(app, env)
}));
}
AppNancyModule
public class AppNancyModule : NancyModule
{
public AppNancyModule()
{
//Get("/", _ => View["index"]);
Get(@"^(.*)$", _ => View["index"]);
}
}
Bootstrapper.cs
public class AppRootPathProvider : IRootPathProvider
{
private readonly IHostingEnvironment _environment;
public AppRootPathProvider(IHostingEnvironment environment)
{
_environment = environment;
}
public string GetRootPath()
{
return _environment.WebRootPath;
}
}
public class Bootstrapper : DefaultNancyBootstrapper
{
readonly IApplicationBuilder _app;
protected override IRootPathProvider RootPathProvider { get; }
public Bootstrapper(IApplicationBuilder app, IHostingEnvironment environment)
{
RootPathProvider = new AppRootPathProvider(environment);
_app = app;
}
protected override void ConfigureApplicationContainer(TinyIoCContainer container)
{
base.ConfigureApplicationContainer(container);
container.Register<IOptions<Endpoints>>(_app.ApplicationServices.GetService<IOptions<Endpoints>>());
container.Register<IReservationService>(_app.ApplicationServices.GetService<IReservationService>());
}
}