检测来自 .NET 核心中间件的静态文件请求

lis*_*ite 6 middleware asp.net-core

我正在编写一些中间件来解析给定请求 URL 的子域以确定网站主题。我想忽略静态文件请求以减少不必要的数据库查找,我想知道是否有更简洁的方法来做到这一点。

这是我迄今为止尝试过的:

var staticFileExtensions = new List<string> { ".css", ".js", ".png", ".ico" };
if (staticFileExtensions.Any(x => httpContext.Request.Path.Value.EndsWith(x)))
{
    await _next(httpContext);
}
else
{
    var hostParts = httpContext.Request.Host.Host.Split('.').ToList();
    if (httpContext.Request.Path.StartsWithSegments(new PathString("/healthcheck"))
    || (hostParts.Count == 6 && _whitelistedDomains.Contains(hostParts[0])))
    {
        httpContext.Items.Add("account", hostParts[0]);
        await _next(httpContext);
    }
    else
    {
        httpContext.Response.StatusCode = (int)HttpStatusCode.NotFound;
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我将它添加到 Startup.cs 的地方:

app.UseStaticFiles();
app.UseSpaStaticFiles();
app.UseDomainWhitelisting();
Run Code Online (Sandbox Code Playgroud)

感觉好像应该有一种更干净的方法来检测要忽略哪些请求,或者我可能遗漏了什么?

Ric*_*chi 9

您可以根据请求使用条件中间件。就像是:

app.UseMiddlewareOne();

app.UseWhen(context => context.Request.Path.StartsWithSegments("/api"), appBuilder =>
{
    appBuilder.UseMiddlewareTwo();
});

app.UseMiddlewareThree();
Run Code Online (Sandbox Code Playgroud)

来源: https://www.devtrends.co.uk/blog/conditional-middleware-based-on-request-in-asp.net-core


Ale*_*lex 6

你不需要。

UseStaticFiles如果请求最终提供静态文件,则在调用后注册的任何中间件都将不会执行。

我刚刚在 Windows 和 Linux 上的 IIS 和 Kestrel 托管下的 .NET 6 和 7 上验证了此行为。

这可能是因为静态文件中间件从不调用_next(context)委托,从而中止整个管道。这称为终端中间件,因为它会短路请求。我希望 MS 文档在某处提到它,但我们总是可以查看源代码......

啊啊,是的,正如我所想,源代码证实了这一点: https: //source.dot.net/#Microsoft.AspNetCore.StaticFiles/StaticFileMiddleware.cs,79

PS 换句话说,要解决OP的问题 - 只需确保在执行域逻辑中间件UseStaticFiles 之前调用即可。还要确保该文件确实存在。如果没有 - 应用程序将继续执行下一个中间件。


Has*_*iny 5

这是一个相当老的问题,但当我遇到类似的问题时,我发现了它,我可以通过检查请求是否以扩展名结束来解决问题并确定静态文件请求。

if(string.IsNullOrEmpty(System.IO.Path.GetExtension(httpContext.Request.Path)))
 //this is normal request
else
 //this can be a file as it ends with some extension (ex*.png) 
Run Code Online (Sandbox Code Playgroud)