接口调优——WebAPI 过滤器,IIS WebDAV
目录
- 1、身份认证过滤器—AuthenticationFilter
- 2、Action 过滤器—ActionFilter
- 3、异常处理过滤器—ExceptionFilterAttribute
- 4、IS WebDAV 模块
本周工作的时候,任务计划已经完成,进行了接口的调优,其中对于过滤器这一块着重进行了调整。
在这个过程中对过滤器的顺序有了一定了解,这里记录下来。
1、身份认证过滤器—AuthenticationFilter
这个是做统一身份认证授权的,这个是最先进来的,进行用户身份验证:
public class BasicAuthenticationFilterAttribute : FilterAttribute, IAuthenticationFilter { public Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken) { if (context.ActionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any()) { return Task.FromResult(0); } // 具体认证业务逻辑 } public Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken) { string realm = context.Request.RequestUri.DnsSafeHost; context.Result = new AddBasicChallengeResult(context.Result, realm); return Task.FromResult(0); } // 错误信息生成 public class AuthenticationFailureResult : IHttpActionResult { public AuthenticationFailureResult(HttpRequestMessage request) { Request = request; } public HttpRequestMessage Request { get; private set; } public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken) { return Task.FromResult(Execute()); } private HttpResponseMessage Execute() { HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.Unauthorized) { RequestMessage = Request }; return response; } } // 认证失败返回质询信息 private class AddBasicChallengeResult : IHttpActionResult { private IHttpActionResult innerResult; private string realm; public AddBasicChallengeResult(IHttpActionResult innerResult, string realm) { this.innerResult = innerResult; this.realm = realm; } public async Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken) { var response = await innerResult.ExecuteAsync(cancellationToken); if (response.StatusCode == HttpStatusCode.Unauthorized) response.Headers.WwwAuthenticate.Add(new AuthenticationHeaderValue("Basic", String.Format("realm=\"{0}\"", realm))); return response; } } }
2、Action 过滤器—ActionFilter
这个是对操作进行统一过滤的过滤器,在这个过滤器里面可以做的事情就很多,我们这里用到了:模型验证、请求信息记录、返回信息格式化;
在这里就分别说下几个具体的业务逻辑;
A、请求信息记录—RequestLogFilter
这里的记录接口请求信息,记录下每个接口请求详情,便于查看记录,具体代码:
public class RequestLogFilterAttribute : ActionFilterAttribute { private readonly string Key = "_RequestTime_"; private readonly string Watch = "_Stopwatch_"; private readonly string Token = ConfigurationManager.AppSettings["Token"].ToString(); public override void OnActionExecuting(HttpActionContext actionContext) { base.OnActionExecuting(actionContext); Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); actionContext.Request.Properties[Key] = DateTime.Now; actionContext.Request.Properties[Watch] = stopWatch; } public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) { Stopwatch stopWatch = actionExecutedContext.Request.Properties[Watch] as Stopwatch; stopWatch.Stop(); // 如果有该特性就不记录请求记录(绕过记录) if (actionExecutedContext.ActionContext.ActionDescriptor.GetCustomAttributes<BypassRequestLogFilterAttribute>().Any()) { return; } // 具体记录接口请求信息 } }
B、模型验证—ValidateModelFilter
这个是模型验证的,对接口的数据有效性进行验证
public class ValidateModelFilterAttribute : ActionFilterAttribute { public override void OnActionExecuting(HttpActionContext actionContext) { if (actionContext.ModelState.IsValid == false) { List<Dictionary<string, string>> allErrors = new List<Dictionary<string, string>>(); var modelState = actionContext.ModelState; foreach (var key in modelState.Keys) { Dictionary<string, string> errorDictionary = new Dictionary<string, string>(); var state = modelState[key]; string[] errorMessages = state.Errors.Select(t => t.ErrorMessage).ToArray(); errorDictionary.Add(key, string.Join(",", errorMessages)); allErrors.Add(errorDictionary); } ResponseData responseData = new ResponseData { MsgCode = 1, Message = "参数有误!", Data = allErrors }; JsonMediaTypeFormatter jsonMediaTypeFormatter = actionContext.Request.GetConfiguration().Formatters.JsonFormatter; actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.BadRequest, responseData, jsonMediaTypeFormatter); } } }
C、返回信息格式化—ResponseFormatterFilter
之所以添加这个过滤器是在我们手机端调用接口的时候,发现返回的信息不是定义好的,
是经过了一种格式化,不能按照我们既定的格式进行解析(分析发现,是请求的时候格式化,返回的信息也按照这个格式化),
所以在过滤器里再对全部的返回信息进行格式化:
public class ResponseFormatterFilterAttribute : ActionFilterAttribute { public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) { if (actionExecutedContext.Response != null && actionExecutedContext.Response.IsSuccessStatusCode) { ObjectContent content = actionExecutedContext.Response.Content as ObjectContent; JsonMediaTypeFormatter jsonMediaTypeFormatter = actionExecutedContext.Request.GetConfiguration().Formatters.JsonFormatter; actionExecutedContext.Response = new HttpResponseMessage { StatusCode = HttpStatusCode.OK, Content = new ObjectContent(content.Value.GetType(), content.Value, jsonMediaTypeFormatter) }; } } }
这几个都是继承自:ActionFilterAttribute,为了比较清晰所以分开放。
对于这种同一级别的过滤器,其执行的先后顺序是:注册在前的先进后出,注册在后的后进先出(大致如下图)
3、异常处理过滤器—ExceptionFilterAttribute
这个是统一处理有异常的过滤器,多错误过滤,返回给客户端的是处理过的,也是最后面一个出去的,过滤器里面有错误也会捕捉到。
具体代码:
public class ExceptionLogFilterAttribute : ExceptionFilterAttribute { public override void OnException(HttpActionExecutedContext actionExecutedContext) { base.OnException(actionExecutedContext); JsonMediaTypeFormatter jsonMediaTypeFormatter = actionExecutedContext.Request.GetConfiguration().Formatters.JsonFormatter; ResponseData responseData; if (actionExecutedContext.Exception is ExceptionEx) { responseData = new ResponseData { MsgCode = 1, Message = actionExecutedContext.Exception.Message }; } else { Exception exceptionData = null; if (ConfigurationManager.AppSettings["ApplicationEnvironment"] == ApplicationEnvironmentEnum.Development.ToString()) { exceptionData = actionExecutedContext.Exception; } responseData = new ResponseData { MsgCode = 1, Message = "系统内部异常!请联系管理员!", Data = exceptionData }; } actionExecutedContext.Response = actionExecutedContext.Request.CreateResponse(HttpStatusCode.BadRequest, responseData, jsonMediaTypeFormatter); } }
对于不同级别的过滤器,执行顺序是:
AuthenticationFilter > ActionFilterAttribute > ExceptionFilterAttribute
4、IIS WebDAV 模块
在每次发布后,出现一个问题:跨域和Put请求不了。
对于这个问题,是已经配置过的怎么还会出现这个问题。
经过反复的测试,原来是 IIS WebDAV 模块,虽然配置了,IIS 是直接修改 Webconfig 文件的,再次发布覆盖了这个文件原有的配置就没了。
对于这个问题,可以在 Webconfig 文件里面配置上,这样可以。
也可以直接去掉 WebDAV 模块,但是卸载不好卸载。可以在 IIS 站点配置文件里面删除 WebDAV 的配置,这样也可以达到效果。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
· 使用C#创建一个MCP客户端