接口调优——WebAPI 过滤器,IIS WebDAV

Posted 漠里

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了接口调优——WebAPI 过滤器,IIS 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 的配置,这样也可以达到效果。

以上是关于接口调优——WebAPI 过滤器,IIS WebDAV的主要内容,如果未能解决你的问题,请参考以下文章

怎么把WebApi接口部署到IIS

WebApi 部署IIS 404.0 not found

webAPI过滤器添加参数签名

WEBAPI使用过滤器对API接口进行验证

VS进程附加的使用

控制台+Owin搭建WebAPI接口服务