POST-запросы не выполняются, когда задано <sessionState cookieless = "AutoDetect" />

Рассмотрим следующий случай:

  • На веб-сервере запущено приложение.NET с <sessionState cookieless="AutoDetect" />,
  • Клиент размещает данные к нему с помощью простого HttpWebRequest (нет печенья).

Этот, казалось бы, простой случай вызывает серьезный сбой.

Поскольку.NET не может определить, является ли запрашивающий агент (HttpWebRequest) поддерживает файлы cookie, он отвечает на запрос POST перенаправлением 302 Found в то же место с помощью:

  • печенье с именем AspxAutoDetectCookie в ответ
  • параметр запроса с именем AspxAutoDetectCookie в переадресованном месте

Затем запрашивающий агент должен запросить новое местоположение, которое HttpWebRequest делает. Когда.NET видит AspxAutoDetectCookie в строке запроса он знает, что это повторный запрос, и он может определить, поддерживаются ли файлы cookie, путем просмотра файла cookie с именем AspxAutoDetectCookie находится в заголовке запроса.

Проблема в том, что большинство запрашивающих агентов (веб-браузеры, HttpWebRequest) обработайте 302 Найденный, как если бы он был 303 См. Другой и сделайте повторный запрос GET, независимо от исходного метода HTTP! Любые данные, отправленные в начальном запросе POST, не пересылаются.

Правильный ответ должен быть 307 Временное перенаправление, которое не меняет метод запроса. (POST-запрос к расположению X перенаправляет на POST- запрос к расположению Y.)

Есть ли способ изменить это поведение в.NET, чтобы POST-запросы не уничтожались?

Информация о перенаправлении 3xx

4 ответа

Решение

Единственное решение, которое я вижу, это добавить AspxAutoDetectCookie=1 на все запросы POST.

Таким образом, ASP.NET никогда не будет перенаправлять запрос, и мы можем полностью избежать вопроса 302 против 307. Если в запрос встроены файлы cookie, ASP.NET обнаружит, что файлы cookie поддерживаются, а если файлы cookie не встроены, то предположит, что они не поддерживаются.

Я знаю, что ветка старая, но другое жизнеспособное решение - создать модуль HTTP для исправления поста http без cookie.

Вот один я использую

            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()
                {}
              }
            }

Есть ли какие-либо проблемы в использовании cookieless="UseDeviceProfile"? Вы можете использовать его как обходное решение.

Вы также видите проблему, если cookiless = true. Вы действительно помогли мне. Я даже не мог понять, что стало причиной этой проблемы, пока я не удалил строку, устанавливающую значение sessionilete cookilesss в true, из своего web.config, не увидел, что проблема исправлена, погуглил мои результаты и нашел эту страницу. Вы помогли объяснить, почему удаление этой строки решило проблему. Можете ли вы дать мне знать, если найдете решение, не включающее изменение способа использования состояния сеанса?

Другие вопросы по тегам