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

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

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

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

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

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

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

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

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

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

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

Ответы [ 4 ]

2 голосов
/ 25 августа 2010

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

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

0 голосов
/ 29 октября 2015

Я знаю, что ветка старая, но другое жизнеспособное решение - создать и модуль 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()
                {}
              }
            }
0 голосов
/ 25 марта 2014

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

0 голосов
/ 20 августа 2010

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

...