【问题标题】:POST requests fail when <sessionState cookieless="AutoDetect" /> is set设置 <sessionState cookieless="AutoDetect" /> 时 POST 请求失败
【发布时间】:2011-04-01 05:52:30
【问题描述】:

考虑以下情况:

  • Web 服务器正在运行带有 &lt;sessionState cookieless="AutoDetect" /&gt; 的 .NET 应用程序。
  • 客户端使用简单的HttpWebRequest(无 cookie)向其发布数据。

这个看似简单的案例却导致重大失败。

由于 .NET 无法确定请求代理 (HttpWebRequest) 是否支持 cookie,它使用 302 Found 重定向到相同位置来响应 POST 请求:

  • 响应中名为 AspxAutoDetectCookie 的 cookie
  • 转发位置中名为AspxAutoDetectCookie 的查询参数

然后请求代理应该请求新位置,HttpWebRequest 会这样做。当 .NET 在查询字符串中看到 AspxAutoDetectCookie 时,它就知道这是一个重新请求,它可以通过查看名为 AspxAutoDetectCookie 的 cookie 是否在请求标头中来确定是否支持 cookie。

问题在于大多数请求代理(Web 浏览器,HttpWebRequest)将 302 Found 视为 303 See Other 并将重新请求设为 GET,而不管原始 HTTP 方法如何!初始 POST 请求中发送的任何数据都不会被转发。

正确的响应应该是307 Temporary Redirect,不会改变请求方式。 (对位置 X 的 POST 请求会重定向到对位置 Y 的 POST 请求。)

有什么方法可以改变 .NET 中的这种行为,使 POST 请求不会被破坏?

Information on 3xx redirection

【问题讨论】:

    标签: .net asp.net http-status-code-302 cookieless http-status-code-307


    【解决方案1】:

    我知道线程很旧,但是另一个可行的解决方案是创建 HTTP 模块来修复 http post over cookieless。

    这是我用的一个

                using System;
                using System.Collections.Specialized;
                using System.Web;
                using System.Web.SessionState;
                using System.IO;
                using System.Text;
    
                namespace CustomModule
                {
                  public sealed class CookielessPostFixModule : IHttpModule
                  {
                    public void Init (HttpApplication application)
                    {
                      application.EndRequest += new
                                  EventHandler(this.Application_EndRequest);
                    }
                    private string ConstructPostRedirection(HttpRequest req,
                                                            HttpResponse res)
                    {
                      StringBuilder build = new StringBuilder();
                      build.Append(
                  "<html>\n<body>\n<form name='Redirect' method='post' action='");
                      build.Append(res.ApplyAppPathModifier(req.Url.PathAndQuery));
                      build.Append("' id='Redirect' >");
                      foreach (object obj in req.Form)
                      {
                        build.Append(string.Format(
                  "\n<input type='hidden' name='{0}' value = '{1}'>",
                          (string)obj,req.Form[(string)obj]));
                      }
                      build.Append(
                  "\n<noscript><h2>Object moved <input type='submit' value='here'></h2></noscript>");
                      build.Append(@"</form>"+
                      "<script language='javascript'>"+
                      "<!--"+
                      "document.Redirect.submit();"+
                      "// -->"+
                      "</script>");
                      build.Append("</body></html>");
                      return build.ToString();
                    }
                    private bool IsSessionAcquired
                    {
                      get
                      {
                        return (HttpContext.Current.Items["AspCookielessSession"]!=null && 
                        HttpContext.Current.Items["AspCookielessSession"].ToString().Length>0);
                      }
                    }
                    private string ConstructPathAndQuery(string[] segments)
                    {
                      StringBuilder build = new StringBuilder(); 
    
                      for (int i=0;i<segments.Length;i++)
                      {
                        if (!segments[i].StartsWith("(") 
                                 && !segments[i].EndsWith(")"))
                          build.Append(segments[i]);
                      }
                      return build.ToString();
                    }
                    private bool IsCallingSelf(Uri referer,Uri newpage)
                    {
                      if(referer==null || newpage==null)
                        return false;
                      string refpathandquery = ConstructPathAndQuery(
                                                        referer.Segments);
                      return refpathandquery == newpage.PathAndQuery;
                    }
                    private bool ShouldRedirect
                    {
                      get
                      {
                        HttpRequest req = HttpContext.Current.Request;
    
                        return (!IsSessionAcquired
                                    && req.RequestType.ToUpper() == "POST"
                          && !IsCallingSelf(req.UrlReferrer,req.Url));
                      }
                    }
                    private void Application_EndRequest(Object source, EventArgs e)
                    {
                      HttpRequest req = HttpContext.Current.Request;
                      HttpResponse res = HttpContext.Current.Response;
                      if (!ShouldRedirect) return;
                      res.ClearContent();
                      res.ClearHeaders();
                      res.Output.Flush();
                      char[] chr = ConstructPostRedirection(req,res).ToCharArray();
                      res.Write(chr,0,chr.Length);
                    }
                    public void Dispose()
                    {}
                  }
                }
    

    【讨论】:

      【解决方案2】:

      我能看到的唯一解决方案是将AspxAutoDetectCookie=1 附加到所有 POST 请求。

      这样,ASP.NET 将永远不会重定向请求,我们可以完全避开 302 与 307 的问题。如果请求中嵌入了 cookie,ASP.NET 将检测到支持 cookie,如果没有嵌入 cookie,则假定它们不支持。

      【讨论】:

      • 如果我们附加标题就可以了:Cookie:AspxAutoDetectCookie=1.
      【解决方案3】:

      使用 cookieless="UseDeviceProfile" 有什么问题吗?您可以将其用作解决方法。

      【讨论】:

      • 很遗憾,我无法使用该设置。它必须与“自动检测”一起使用。
      猜你喜欢
      • 2021-08-13
      • 2011-09-07
      • 2013-02-08
      • 2013-03-21
      • 1970-01-01
      • 2017-10-30
      • 1970-01-01
      • 2021-11-28
      • 1970-01-01
      相关资源
      最近更新 更多