如何使用Owin中间件拦截404 [英] How to intercept 404 using Owin middleware

查看:314
本文介绍了如何使用Owin中间件拦截404的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

首先让我解释的背景。我正在试图嫁给使用Web API通过OWIN-配置IIS上承载的,现在后端服务器的一个项目,但在面向未来使用AngularJS一个前端潜在的其他OWIN支持的主机。

First let me explain the background. I am working on a project that attempts to marry a backend server that uses Web API configured via OWIN- hosted on IIS now, but potentially other OWIN-supported hosts in the future- to a frontend using AngularJS.

该AngularJS前端完全是静态内容。我完全避免服务器端的技术,如MVC /剃须刀,WebForms的,捆绑,任何与前端和它使用的资产做,而是推迟到使用Node.js的,咕噜/咕嘟咕嘟等方面的最新最好的技术。处理CSS编辑,捆绑,缩小等。对于原因,我不会进入这里,我一直在不同的地点的前端和服务器项目在同一项目中(而不是直接把它们粘在所有主机项目(见粗如下图)。

The AngularJS frontend is entirely static content. I completely avoid server-side technologies such as MVC/Razor, WebForms, Bundles, anything that has to do with the frontend and the assets it uses, and defer instead to the latest and greatest techniques using Node.js, Grunt/Gulp, etc. to handle CSS compilation, bundling, minification, etc. For reasons I won't go into here, I keep the frontend and server projects in separate locations within the same project (rather than stick them all in the Host project directly (see crude diagram below).

MyProject.sln
server
  MyProject.Host
     MyProject.Host.csproj
     Startup.cs
     (etc.)
frontend
  MyProjectApp
     app.js
     index.html
     MyProjectApp.njproj
     (etc.)

所以,尽可能的前端方面,所有我需要做的就是让我的主机为我的静态内容。在防爆press.js,这是微不足道的。随着OWIN,我能够做到这一点很容易使用 Microsoft.Owin.StaticFiles 中间件,以及它的工作原理伟大的(这是非常光滑)。

So as far as the frontend is concerned, all I need to do is get my Host to serve my static content. In Express.js, this is trivial. With OWIN, I was able to do this easily using Microsoft.Owin.StaticFiles middleware, and it works great (it's very slick).

下面是我的 OwinStartup 的配置:

string dir = AppDomain.CurrentDomain.RelativeSearchPath; // get executing path
string contentPath = Path.GetFullPath(Path.Combine(dir, @"../../../frontend/MyProjectApp")); // resolve nearby frontend project directory

app.UseFileServer(new FileServerOptions
{
    EnableDefaultFiles = true,
    FileSystem = new PhysicalFileSystem(contentPath),
    RequestPath = new PathString(string.Empty) // starts at the root of the host
});

// ensure the above occur before map handler to prevent native static content handler
app.UseStageMarker(PipelineStage.MapHandler);

渔获

基本上,它只是在举办前端/ MyProjectApp ,就好像它是正确的MyProject.Host根内的一切。所以很自然的,如果你要求一个不存在的文件,IIS会生成一个404错误。

The Catch

Basically, it just hosts everything in frontend/MyProjectApp as if it were right inside the root of MyProject.Host. So naturally, if you request a file that doesn't exist, IIS generates a 404 error.

现在,因为这是一个AngularJS应用程序,它支持 html5mode ,我将有一些路线是不是在服务器上的物理文件,但在AngularJS应用路由处理。如果用户要拖拽到一个AngularJS(index.html的以外的任何其他或实际存在,在这个例子中的文件),我会得到一个404,即使这条路线可能在AngularJS应用有效。因此,我需要我的OWIN中间件返回 index.html的中的事件文件请求的文件不存在,让我AngularJS应用程序数字,如果它真的是一个404

Now, because this is an AngularJS app, and it supports html5mode, I will have some routes that aren't physical files on the server, but are handled as routes in the AngularJS app. If a user were to drop onto an AngularJS (anything other than index.html or a file that physically exists, in this example), I would get a 404 even though that route might be valid in the AngularJS app. Therefore, I need my OWIN middleware to return the index.html file in the event a requested file does not exist, and let my AngularJS app figure out if it really is a 404.

如果你熟悉SPA和AngularJS,这是一个正常的,直接的方法。如果我使用MVC或ASP.NET路由,我可以只设置一个MVC控制器返回我的 index.html的,或沿着这些线路的东西缺省路由。不过,我已经说过我不使用MVC和我试图保持这个简单,重量轻越好。

If you're familiar with SPAs and AngularJS, this is a normal and straight-forward approach. If I were using MVC or ASP.NET routing, I could just set the default route to an MVC controller that returns my index.html, or something along those lines. However, I've already stated I'm not using MVC and I'm trying to keep this as simple and lightweight as possible.

<一个href=\"http://stackoverflow.com/questions/25916851/wrapping-staticfilemiddleware-to-redirect-404-errors\">This用户也有类似的困境,并与IIS重写解决它。在我而言,这是行不通的,因为)我的内容物理上不存在那里的URL重写模块可以找到它,所以它的总是的回报的index.html 和b)我想要的东西,不依赖于IIS,但OWIN中间件内处理,因此可以灵活使用。

This user had a similar dilemma and solved it with IIS rewriting. In my case, it doesn't work because a) my content doesn't physically exist where the rewrite URL module can find it, so it always returns index.html and b) I want something that doesn't rely on IIS, but is handled within OWIN middleware so it can be used flexibly.

简单,我怎么能拦截404未找​​到并返回的内容(注:的的重定向)我的文件服务器 -served index.html的使用OWIN中间件?

Simple, how can I intercept a 404 Not Found and return the content of (note: not redirect) my FileServer-served index.html using OWIN middleware?

推荐答案

我写了这个小中间件组件,但我不知道这是否是矫枉过正,效率不高,或者有其他缺陷。基本上,它只是需要在同一个 FileServerOptions FileServerMiddleware 使用,是最重要的部分文件系统我们使用。它被放置在上述中间件之前确实看到一个快速检查,如果被请求的路径存在。如果不是,则请求路径被改写为index.html的,并且正常StaticFileMiddleware将从那里接管。

I wrote this little middleware component, but I don't know if it's overkill, inefficient, or if there are other pitfalls. Basically it just takes in the same FileServerOptions the FileServerMiddleware uses, the most important part being the FileSystem we're using. It is placed before the aforementioned middleware and does a quick check to see if the requested path exists. If not, the request path is rewritten as "index.html", and the normal StaticFileMiddleware will take over from there.

显然,它可以站在清理重复使用,其中包括一种方法来定义不同的默认文件不同的根路径(例如,从/特征1,也就是缺少应使用/feature1/index.html,同样要求任何以/ feature2之/feature2/default.html,等)。

Obviously it could stand to be cleaned up for reuse, including a way to define different default files for different root paths (e.g. anything requested from "/feature1" that is missing should use "/feature1/index.html", likewise with "/feature2" and "/feature2/default.html", etc.).

但现在,它这为我工作。这对Microsoft.Owin.StaticFiles依赖,效果显着。

But for now, it this works for me. This has a dependency on Microsoft.Owin.StaticFiles, obviously.

public class DefaultFileRewriterMiddleware : OwinMiddleware
{
    private readonly FileServerOptions _options;

    /// <summary>
    /// Instantiates the middleware with an optional pointer to the next component.
    /// </summary>
    /// <param name="next"/>
    /// <param name="options"></param>
    public DefaultFileRewriterMiddleware(OwinMiddleware next, FileServerOptions options) : base(next)
    {
        _options = options;
    }

    #region Overrides of OwinMiddleware

    /// <summary>
    /// Process an individual request.
    /// </summary>
    /// <param name="context"/>
    /// <returns/>
    public override async Task Invoke(IOwinContext context)
    {
        IFileInfo fileInfo;
        PathString subpath;

        if (!TryMatchPath(context, _options.RequestPath, false, out subpath) ||
            !_options.FileSystem.TryGetFileInfo(subpath.Value, out fileInfo))
        {
            context.Request.Path = new PathString(_options.RequestPath + "/index.html");
        }

        await Next.Invoke(context);
    }

    #endregion

    internal static bool PathEndsInSlash(PathString path)
    {
        return path.Value.EndsWith("/", StringComparison.Ordinal);
    }

    internal static bool TryMatchPath(IOwinContext context, PathString matchUrl, bool forDirectory, out PathString subpath)
    {
        var path = context.Request.Path;

        if (forDirectory && !PathEndsInSlash(path))
        {
            path += new PathString("/");
        }

        if (path.StartsWithSegments(matchUrl, out subpath))
        {
            return true;
        }
        return false;
    }
}

这篇关于如何使用Owin中间件拦截404的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆