2014-09-18 18 views
7

Sto cercando di iniettare un middleware personalizzato nella mia pipeline OWIN che avvolge lo StaticFileMiddleware disponibile da MS per supportare la modalità HTML 5 in AngularJS. Ho seguito questa guida: http://geekswithblogs.net/shaunxu/archive/2014/06/10/host-angularjs-html5mode-in-asp.net-vnext.aspxWrapping StaticFileMiddleware per reindirizzare gli errori 404

Da quello che posso capire su come dovrebbe funzionare, il mio middleware passa le richieste al middleware dei file statici e quindi se non riesce a risolvere quelle richieste (es. , una richiesta per un percorso angolare 5 HTML, "/ qualunque"), restituisce invece la pagina angolare di base in modo che una richiesta valida per un percorso HTML 5 funzioni.

Il mio problema è che il risultato di invocare il middleware interno sembra sempre essere un codice di stato 200, anche se nel mio browser ottengo un 404, che mi lascia grattarmi la testa. Ecco il mio codice di riferimento:

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

risposta

17

Dalla tua domanda non sono sicuro se stai usando IIS o selfhost. Se si utilizza IIS, è disponibile una soluzione molto più pulita/più veloce rispetto alla messaggistica con il middleware owin: È possibile utilizzare il motore di riscrittura IIS, copiare quanto segue all'interno della propria configurazione Web.

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

Questa linea consente a tutti i file per essere servito normalmente:

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

questa linea permette l'API per essere servito normalmente

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

Tutto il resto diventa index.html

+0

Grazie - Stavo usando IIS e questo ha fatto il trucco meravigliosamente. –

+1

Ricevo un errore interno del server 500.19 con questo, qualche idea? – georgiosd

+0

@georgiosd il postato deve trovarsi all'interno di un blocco . Assicurati anche di non includere "..."; D – FLGMwt

1

Non volevo essere legato a IIS, con il modo in cui il nucleo di asp.net va avanti. Ecco come sono arrivato a lavorare con OWIN:

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

avevo bisogno di chiamare next() prima ho controllato per il codice di stato, perché presumo l'altro middleware non imposterà il 404 fino a quando tutto il middleware ha la possibilità di gestire esso.

DISCLAIMER: Sto solo iniziando a esplorare l'hosting basato su OWIN, quindi mentre questo sembra funzionare, potrebbero esserci alcune best practice.

Problemi correlati