Обтекание StaticFileMiddleware для перенаправления ошибок 404
Я пытаюсь внедрить пользовательское промежуточное ПО в мой конвейер OWIN, который оборачивает StaticFileMiddleware
доступно от MS для поддержки режима HTML 5 в AngularJS. Я следовал этому руководству: http://geekswithblogs.net/shaunxu/archive/2014/06/10/host-angularjs-html5mode-in-asp.net-vnext.aspx
Из того, что я могу понять, как это должно работать, мое промежуточное программное обеспечение передает запросы промежуточному программному обеспечению статического файла, а затем, если оно не может разрешить эти запросы (т. Е. Запрос на угловой путь HTML 5, "/ что угодно ") вместо этого он возвращает базовую угловую страницу, чтобы сработал сложный запрос пути HTML 5.
Моя проблема в том, что результатом вызова внутреннего промежуточного программного обеспечения всегда является код состояния 200, хотя в моем браузере я получаю 404, что оставляет меня почесывать голову. Вот мой код для справки:
public static class AngularServerExtension
{
public static IAppBuilder UseAngularServer(this IAppBuilder builder, string rootPath, string entryPath)
{
var options = new AngularServerOptions()
{
FileServerOptions = new FileServerOptions()
{
EnableDirectoryBrowsing = false,
FileSystem = new PhysicalFileSystem(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, rootPath))
},
EntryPath = new PathString(entryPath)
};
builder.UseDefaultFiles(options.FileServerOptions.DefaultFilesOptions);
return builder.Use(new Func<AppFunc, AppFunc>(next => new AngularServerMiddleware(next, options).Invoke));
}
}
public class AngularServerMiddleware
{
private readonly AngularServerOptions _options;
private readonly AppFunc _next;
private readonly StaticFileMiddleware _innerMiddleware;
public AngularServerMiddleware(AppFunc next, AngularServerOptions options)
{
_next = next;
_options = options;
_innerMiddleware = new StaticFileMiddleware(_next, options.FileServerOptions.StaticFileOptions);
}
public async Task Invoke(IDictionary<string, object> environment)
{
IOwinContext context = new OwinContext(environment);
// try to resolve the request with default static file middleware
await _innerMiddleware.Invoke(environment);
Debug.WriteLine(context.Request.Path + ": " + context.Response.StatusCode);
// *** Right here is where I would expect a 404 but I get a 200 when debugging,
// even though my browser eventually returns a 404
// route to root path if the status code is 404
// and need support angular html5mode
if (context.Response.StatusCode == 404 && _options.Html5Mode)
{
context.Request.Path = _options.EntryPath;
await _innerMiddleware.Invoke(environment);
Console.WriteLine(">> " + context.Request.Path + ": " + context.Response.StatusCode);
}
}
}
public class AngularServerOptions
{
public FileServerOptions FileServerOptions { get; set; }
public PathString EntryPath { get; set; }
public bool Html5Mode
{
get
{
return EntryPath.HasValue;
}
}
public AngularServerOptions()
{
FileServerOptions = new FileServerOptions();
EntryPath = PathString.Empty;
}
}
2 ответа
От вашего вопроса я не уверен, используете ли вы IIS или selfhost. Если вы используете IIS, есть гораздо более чистое / быстрое решение, чем путаться с промежуточным ПО owin: вы можете использовать механизм перезаписи IIS, скопировав следующее в веб-конфигурацию.
<system.webServer>
<rewrite>
<rules>
<!--Redirect selected traffic to index -->
<rule name="Index Rule" stopProcessing="true">
<match url=".*" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_URI}" matchType="Pattern" pattern="^/api/" negate="true" />
</conditions>
<action type="Rewrite" url="/index.html" />
</rule>
</rules>
</rewrite>
...
</system.webServer>
Эта строка позволяет нормально обслуживать все файлы:
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
эта строка позволяет API обслуживаться нормально
<add input="{REQUEST_URI}" matchType="Pattern" pattern="^/api/" negate="true" />
Все остальное получает index.html
Я не хотел быть привязанным к IIS с тем, как движется ядро asp.net. Вот как я заставил его работать, используя OWIN:
// catch all for html5/angular2 client routing urls that need to be redirected back to index.html
// for original, see: http://stackru.com/questions/27036448/how-to-intercept-404-using-owin-middleware/30741479#30741479
app.Use(async (ctx, next) =>
{
// execute the rest of the pipeline
// though really, we're last in this configuration
// but, this allows the other static file handlers
// and web api route handlers to fail
await next();
// double check that we have a 404
// we could also double check that we didn't request a file (with an extension of some sort)
if (ctx.Response.StatusCode != 404)
{
return;
}
// we have a 404, serve our default index.html
var middleware = new StaticFileMiddleware(
env => next(), new StaticFileOptions
{
FileSystem = new PhysicalFileSystem("./wwwroot"),
RequestPath = PathString.Empty
});
ctx.Request.Path = new PathString("/index.html");
await middleware.Invoke(ctx.Environment);
});
Мне нужно было позвонить next()
прежде чем я проверил код состояния, потому что я предполагаю, что другое промежуточное ПО не установит 404, пока все промежуточное ПО не сможет его обработать.
ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: Я только начинаю изучать хостинг на основе OWIN, так что, хотя это, кажется, работает, могут быть некоторые не лучшие практики.