在WebApi中,常常使用到静态的文件访问,比如图片、Html、压缩包、运行程序等等,当用户在浏览器直接输入 该静态文件的访问是不会经过默认的api控制器路由,举个例子,在api根目录放一个 setup.exe文件,然后创建一个控制器,按如下方式强制指定路由。
[Route("setup.exe")]
[HttpGet]
[AllowAnonymous]
public object GetFile()
{
return "API Control Action Response";
}
当用户在浏览器输入:http://xxxxxx.com/setup.exe 时,由于IIS的MIME类型中已经定义.exe扩展名的文件,所以HttpServer直接返回该文件,也就是用户的浏览器直接弹出setup.exe文件的下载。在本地调试时,即使在上述的Action内添加断点也不会进入,并且也不会触发API的过滤器。
需求1:现在做了一个很酷炫的下载界面,但是前期对外投放了大量http://xxxxxx.com/setup.exe
的链接,此时希望用户访问该链接时能重定向到下载界面。
需求2:希望对特定后缀名的静态文件进行鉴权操作(虽然有点奇怪的需求,但是实际还真会出现),比如输入http://xxxxxx.com/demo.zip
后如果没鉴权那就先弹出登录界面或密码输入界面,完成后才弹出文件下载。
针对需求1,其实可以在IIS中配置重定向功能,或者在WebApi项目的Web.config文件中配置重定向,这里不详细进行说明;这里以在项目中拦截静态文件请求实现。
针对需求2,思路是先拦截静态文件访问,然后进行鉴权判定,如果已经鉴权就返回文件,如果未鉴权就跳转鉴权界面,并将当前路URL以参数转过去,等待鉴权成功作为回调跳转。
废话少说,直接开撸代码,在Global.asax中,添加Application_BeginRequest与Application_AcquireRequestState方法,如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http;
using System.Web.Routing;
namespace FirmwareVersionSYS.Web.Api
{
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
}
public override void Init()
{
this.PostAuthenticateRequest += (sender, e) => HttpContext.Current.SetSessionStateBehavior(System.Web.SessionState.SessionStateBehavior.Required);
base.Init();
}
protected void Application_BeginRequest(object sender, EventArgs e)
{
/* 处理需求1
* 当请求的URL为 /setup.exe 路由的时候就跳转到/download.html
*/
if (Request.Url.AbsolutePath.ToLower().Equals("/setup.exe"))
{
Response.Redirect("/download.html");
}
}
protected void Application_AcquireRequestState(object sender, EventArgs e)
{
/* 处理需求2
* 当请求的文件为.zip时 鉴定Session["UserId"]不为空就允许下载 否则跳转鉴权界面
* 鉴权界面具体自行处理,就是需要Session["UserId"]赋值
*/
if (Request.Url.AbsolutePath.ToLower().EndsWith(".zip") && HttpContext.Current.Session["UserId"] == null)
{
Response.Redirect("auth/login?callbak=" + Request.Url.AbsolutePath);
}
}
}
}
特别注意,需要在Web.config 中配置对所有链接进行处理
<system.webServer>
<!--处理所有的请求,在Global.asax中可以在Application_BeginRequest方法进行拦截-->
<modules runAllManagedModulesForAllRequests="true" />
</system.webServer>
大功告成!!