2014-09-18 12 views
7

Ich versuche, eine benutzerdefinierte Middleware in meine OWIN-Pipeline zu injizieren, die die StaticFileMiddleware von MS zur Verfügung stellt, um HTML 5-Modus in AngularJS zu unterstützen. Ich folge dieser Anleitung: http://geekswithblogs.net/shaunxu/archive/2014/06/10/host-angularjs-html5mode-in-asp.net-vnext.aspxWrapping StaticFileMiddleware 404 Fehler umleiten

Von was ich sammeln kann, wie dies funktionieren soll, ist meine Middleware Anfragen an die statische Datei Middleware weiterzugeben, und dann, wenn es diese Anfragen nicht lösen kann (dh , eine Anfrage für einen HTML 5-Winkelpfad "/ was auch immer"), gibt es stattdessen die Basiswinkelseite zurück, so dass eine harte Anfrage für einen HTML 5-Pfad funktioniert.

Mein Problem ist, dass das Ergebnis des Aufrufs der inneren Middleware immer ein Statuscode von 200 zu sein scheint, obwohl ich in meinem Browser einen 404 bekomme, der mich am Kopf kratzt. Hier ist mein Code für die Referenz:

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; 
    } 
} 

Antwort

17

Von Ihrer Frage bin ich nicht sicher, ob Sie IIS oder Selfhost verwenden. Wenn Sie IIS verwenden, gibt es eine viel sauberere/schnellere Lösung als mit owin Middleware: Sie können IIS Rewrite Engine verwenden, kopieren Sie die folgenden in Ihrer Webkonfiguration.

<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> 

Diese Linie ermöglicht es, alle Dateien in der Regel bedient werden:

<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" /> 

dieser Linie ermöglicht die api normalerweise

serviert werden sonst
<add input="{REQUEST_URI}" matchType="Pattern" pattern="^/api/" negate="true" /> 

Alles wird index.html

+0

Danke - ich war mit IIS und das hat den Trick wunderbar. –

+1

Ich bekomme einen 500.19 Interner Server Fehler mit diesem, irgendwelche Ideen? – georgiosd

+0

@georgiosd der Beitrag muss innerhalb eines -Blocks sein. Stellen Sie außerdem sicher, dass das "..." nicht enthalten ist. D – FLGMwt

1

Ich wollte nicht mit IIS verbunden sein, mit der Art, wie der asp.net-Kern voranschreitet. Hier ist, wie ich es bekam mit OWIN zu arbeiten:

// catch all for html5/angular2 client routing urls that need to be redirected back to index.html 
// for original, see: http://stackoverflow.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); 
}); 

Ich brauchte next() anrufen, bevor ich für den Statuscode überprüft, weil ich die andere Middleware übernehmen nicht die 404 gesetzt, bis alle Middleware eine Chance hat, zu handhaben es.

DISCLAIMER: Ich beginne gerade, OWIN-basiertes Hosting zu erforschen, also, während dies zu funktionieren scheint, könnte es einige nicht-Best Practices geben.