zoukankan      html  css  js  c++  java
  • 在MVC里面使用Response.Redirect方法后记得返回EmptyResult

    在ASP.NET MVC中我们很多时候都会在拦截器和Controller中直接使用Response.Redirect方法做跳转,但是实际上Response.Redirect方法执行后ASP.NET并不会立即结束当前请求的执行,而是要过一段时间才会终止当前请求的执行,然后命令客户端浏览器去访问Response.Redirect方法中传入的新的URL地址。这会导致一个问题,有时候我们希望Response.Redirect方法执行后后面的代码就取消执行了,因为这并不是我们预期的行为,当代码执行了Response.Redirect方法后,如果其后面的部分代码还继续在执行甚至有可能报错。

    比如在下面的代码中我们演示了在MVC的IAuthorizationFilter拦截器中,如果用户没有登录应该立刻停止当前页面的请求,然后跳转到登录页面。我们使用了Response.Redirect方法来做跳转。

     1 public class AuthenticationFilterAttribute:ActionFilterAttribute,IAuthorizationFilter,IActionFilter
     2     {
     3         #region IAuthorizationFilter Members
     4 
     5         public void OnAuthorization(AuthorizationContext filterContext)
     6         {
     7 
     8             string curActionName = filterContext.ActionDescriptor.ActionName;
     9             string curControllerName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;
    10 
    11             if (!filterContext.HttpContext.Request.IsAuthenticated && (curControllerName.ToLower() != "login" || curActionName.ToLower() != "index"))
    12             {
    13                 filterContext.HttpContext.Response.Redirect(LoginHelper.LoginPageUrl, true);
    14                 return;
    15             }
    16         }
    17 
    18         #endregion
    19     }

    结果我惊讶的发现即便代码在上面13行Response.Redirect了,ASP.NET还是执行了当前请求URL对应Controller的Action中的代码,甚至执行了Action返回的View的Razor引擎代码。。。虽然最终这个view的内容没有呈现给客户端浏览器,浏览器最后还是正确跳转到了登录页。但是根据调试我们发现即便是我们执行了Response.Redirect方法,ASP.NET之后还是执行了一大堆本不该执行的代码

    所以这个时候我们需要用到EmptyResult这个对象,我们将上面的代码改成如下所示:

     1 public class AuthenticationFilterAttribute:ActionFilterAttribute,IAuthorizationFilter,IActionFilter
     2     {
     3         #region IAuthorizationFilter Members
     4 
     5         public void OnAuthorization(AuthorizationContext filterContext)
     6         {
     7 
     8             string curActionName = filterContext.ActionDescriptor.ActionName;
     9             string curControllerName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;
    10 
    11             if (!filterContext.HttpContext.Request.IsAuthenticated && (curControllerName.ToLower() != "login" || curActionName.ToLower() != "index"))
    12             {
    13                 filterContext.HttpContext.Response.Redirect(LoginHelper.LoginPageUrl, true);
    14                 filterContext.Result = new EmptyResult();//加入EmptyResult就告诉ASP.NET MVC在本拦截器执行结束后,不必再为当前请求执行Controller中Action的代码
    15                 return;
    16             }
    17         }
    18 
    19         #endregion
    20     }

    那么ASP.NET MVC在执行完上面的IAuthorizationFilter拦截器后,就会发现EmptyResult被赋值在了参数filterContext的Result属性上,就会终止执行Controller的Action,立即结束当前请求的执行,不会再去执行多余的代码了。其实filterContext的Result属性只要在IAuthorizationFilter拦截器中被赋值了不为null,就不会执行Controller的Action了,同时在该IAuthorizationFilter拦截器之后注册的其它Filter拦截器也都不会被执行了。

    比如在ASP.NET Core MVC(由于在ASP.NET MVC中JsonResult的构造函数不带参数,所以在拦截器中使用JsonResult的意义不大,不如就用EmptyResult)中的IAuthorizationFilter拦截器中,我们也可以选择给context的Result属性赋值为JsonResult:

    using Microsoft.AspNetCore.Mvc;
    using Microsoft.AspNetCore.Mvc.Filters;
    using System;
    
    namespace WebApi.Filters
    {
        public class AuthorizationFilterAttribute : Attribute, IAuthorizationFilter
        {
            public AuthorizationFilterAttribute()
            {
    
            }
    
            public void OnAuthorization(AuthorizationFilterContext context)
            {
                context.Result = new JsonResult(new { message = "Http请求被AuthorizationFilter拦截" });//加入JsonResult来告诉ASP.NET Core MVC在本拦截器执行结束后,不必再为当前请求执行Controller中Action的代码,同时取消执行在本拦截器之后注册的其它Filter拦截器,此外会通过Http的Response返回一个{"message":"Http请求被AuthorizationFilter拦截"}的Json对象到客户端浏览器
            }
        }
    }

    只不过这样会同时返回一个Json对象给客户端浏览器。

    在拦截器中,还可以结合设置StatusCode和EmptyResult,来返回特定状态码的Http响应,例如下面我们就展示了如何在IAuthorizationFilter拦截器中,返回401状态的Http响应

    using System;
    using System.IO;
    using System.Text;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.AspNetCore.Mvc.Filters;
    
    namespace WebApi.Filters
    {
        public class AuthorizationFilterAttribute : Attribute, IAuthorizationFilter
        {
            public AuthorizationFilterAttribute()
            {
    
            }
    
            /// <summary>
            /// 设置StatusCode和EmptyResult,返回401状态的Http响应,并发送一段html为Http响应体
            /// </summary>
            public void OnAuthorization(AuthorizationFilterContext context)
            {
                context.HttpContext.Response.ContentType = "text/html; charset=utf-8";//设置Http响应类型为text/html,编码为utf-8
                context.HttpContext.Response.StatusCode = 401;//设置Http响应状态码为401
    
                using (StreamWriter sw = new StreamWriter(context.HttpContext.Response.Body, Encoding.UTF8))
                {
                    sw.Write("<html><head></head><body><h1>Unauthorized!</h1></body></html>");
                }
    
                context.Result = new EmptyResult();//加入EmptyResult就告诉ASP.NET Core MVC在本拦截器执行结束后,不必再为当前请求执行Controller中Action的代码,同时取消执行在本拦截器之后注册的其它Filter拦截器
            }
    
            /// <summary>
            /// 设置UnauthorizedResult,返回401状态的Http响应
            /// </summary>
            //public void OnAuthorization(AuthorizationFilterContext context)
            //{
            //    context.Result = new UnauthorizedResult();//加入UnauthorizedResult就告诉ASP.NET Core MVC在本拦截器执行结束后,不必再为当前请求执行Controller中Action的代码,同时取消执行在本拦截器之后注册的其它Filter拦截器,并且返回401状态的Http响应
            //}
        }
    }

    所以很多时候我们在ASP.NET中使用Response.Redirect方法时要相当小心,一定要知道Response.Redirect方法执行后并不等于代码就结束执行了,还要考虑到后面的代码一旦被误执行会有什么后果,有什么办法可以避免。在MVC中使用EmptyResult就是个不错的选择。

  • 相关阅读:
    使用boost中的property_tree实现配置文件
    C++ 中使用boost::property_tree读取解析ini文件
    引用计数的原理和实例
    C++智能指针(auto_ptr)详解
    Oracle数据库用户锁定原因以及处理方式(ORA-28000)
    Address already in use : connect 的解决办法
    JMeter之Ramp-up Period(in seconds)说明(可同时并发)
    JMETER压力测试报错:JAVA.NET.BINDEXCEPTION: ADDRESS ALREADY IN USE: CONNECT
    spring cloud学习填坑笔记
    使用JMeter进行一次简单的带json数据的post请求测试,json可配置参数
  • 原文地址:https://www.cnblogs.com/OpenCoder/p/5421464.html
Copyright © 2011-2022 走看看