Поддержка заголовка запроса OPTIONS на странице aspx - PullRequest
4 голосов
/ 06 июля 2011

Я поддерживаю службу, которая принимает пост в форме, и при добавлении поддержки запросов CORS я столкнулся с проблемой в Firefox 3.6, где он отправляет предварительный запрос с заголовком запроса OPTIONS.

У меня не было проблем с добавлением необходимых заголовков ответов Access-Control-Allow-Origin с общей страницей обработчика http, но у меня возникли проблемы с полноразмерной страницей aspx. Это определенно не касается Page_Load, и я не могу понять, где в жизненном цикле страницы он застревает.

У кого-нибудь есть идеи?

Спасибо!

Ответы [ 2 ]

9 голосов
/ 06 июля 2011

Вы можете сделать это с HttpModule и HttpHandler

Я думаю, что кое-что из этого появилось в какой-то статье, а другие ее части были разработаны собственными силами ... поэтому, если что-то из этого пришло откуда-то еще, я заранее прошу прощения за то, что не дал должную оценку:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace YourNamespaceHere
{
    using System;
    using System.Web; 
    using System.Collections;

    public class CrossOriginModule : IHttpModule {
        public String ModuleName {
            get { return "CrossOriginModule"; } 
        }    

        public void Init(HttpApplication application) {
            application.BeginRequest += (new EventHandler(this.Application_BeginRequest));
        }

        private void Application_BeginRequest(Object source, EventArgs e) {
            HttpApplication application = (HttpApplication)source;
            HttpContext context = application.Context;
            CrossOriginHandler.SetAllowCrossSiteRequestOrigin(context);
        }

        public void Dispose() 
        {
        }
    }

   public class CrossOriginHandler : IHttpHandler
    {
        #region IHttpHandler Members
        public bool IsReusable
        {
            get { return true; }
        }

        public void ProcessRequest(HttpContext context)
        {
            //Clear the response (just in case)
            ClearResponse(context);

            //Checking the method
            switch (context.Request.HttpMethod.ToUpper())
            {
                //Cross-Origin preflight request
                case "OPTIONS":
                    //Set allowed method and headers
                    SetAllowCrossSiteRequestHeaders(context);
                    //Set allowed origin
                    //This happens for us with our module:
                    SetAllowCrossSiteRequestOrigin(context);
                    //End
                    context.Response.End();
                    break;

                default:
                    context.Response.Headers.Add("Allow", "OPTIONS");
                    context.Response.StatusCode = 405;
                    break;
            }

            context.ApplicationInstance.CompleteRequest();
        }
        #endregion

        #region Methods
        protected void ClearResponse(HttpContext context)
        {
            context.Response.ClearHeaders();
            context.Response.ClearContent();
            context.Response.Clear();
        }

        protected void SetNoCacheHeaders(HttpContext context)
        {
            context.Response.Cache.SetExpires(DateTime.UtcNow.AddDays(-1));
            context.Response.Cache.SetValidUntilExpires(false);
            context.Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches);
            context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
            context.Response.Cache.SetNoStore();
        }
        #endregion

        public static void SetAllowCrossSiteRequestHeaders(HttpContext context)
        {
            string requestMethod = context.Request.Headers["Access-Control-Request-Method"];

            context.Response.AppendHeader("Access-Control-Allow-Methods", "GET,POST");

            //We allow any custom headers
            string requestHeaders = context.Request.Headers["Access-Control-Request-Headers"];
            if (!String.IsNullOrEmpty(requestHeaders))
                context.Response.AppendHeader("Access-Control-Allow-Headers", requestHeaders);
        }

        public static void SetAllowCrossSiteRequestOrigin(HttpContext context)
        {
            string origin = context.Request.Headers["Origin"];
            if (!String.IsNullOrEmpty(origin))
                context.Response.AppendHeader("Access-Control-Allow-Origin", origin);
            else
                //This is necessary for Chrome/Safari actual request
                context.Response.AppendHeader("Access-Control-Allow-Origin", "*");
        }
    }
}

И в Web.config:

  ...
  <system.webServer>
     ...
     <modules runAllManagedModulesForAllRequests="true">
     ...
           <add name="CrossOriginModule" preCondition="managedHandler" type="YOURNANMESPACEHERE.CrossOriginModule, ASSEMBLYNAME" />
    </modules>
    <handlers>
           <add name="CrossOrigin" verb="OPTIONS" path="*" type="YOURNAMESPACEHERE.CrossOriginHandler, ASSEMBLYNAME" />
    </handlers>
  </system.webServer>
5 голосов
/ 29 июня 2016

Ответ Стива удивителен, он неизбежно приводит меня к решению в моем случае, поэтому я проголосовал за него.Тем не менее, мне кажется, что HttpHandler не может быть явно необходимым.Поэтому я настроил CORS строго в самом модуле, который подключается к конвейеру запросов.Мой код:

using System;
using System.Web;

namespace NAMESPACE.HttpModules
{
    public class CrossOriginModule : IHttpModule
    {
        public String ModuleName
        {
            get { return "CrossOriginModule"; }
        }

        public void Init(HttpApplication application)
        {
            application.BeginRequest += (new EventHandler(this.Application_BeginRequest));
        }

        private void Application_BeginRequest(Object source, EventArgs e)
        {
            HttpApplication application = (HttpApplication)source;
            HttpContext context = application.Context;

            string httpMethod = context.Request.HttpMethod.ToUpper();

            //preflight
            if (httpMethod == "OPTIONS")
            {
                ClearResponse(context);

                //Set allowed method and headers
                SetAllowCrossSiteRequestHeaders(context);
                //Set allowed origin
                SetAllowCrossSiteRequestOrigin(context);

                //end request
                context.ApplicationInstance.CompleteRequest();
            }
            else
            {
                SetAllowCrossSiteRequestOrigin(context);
            }

        }
        static void SetAllowCrossSiteRequestHeaders(HttpContext context)
        {
            string requestMethod = context.Request.Headers["Access-Control-Request-Method"];

            context.Response.AppendHeader("Access-Control-Allow-Methods", "GET,POST");

            //We allow any custom headers
            string requestHeaders = context.Request.Headers["Access-Control-Request-Headers"];
            if (!String.IsNullOrEmpty(requestHeaders))
                context.Response.AppendHeader("Access-Control-Allow-Headers", requestHeaders);

            //allow credentials
            context.Response.AppendHeader("Access-Control-Allow-Credentials", "true");
        }

        static void SetAllowCrossSiteRequestOrigin(HttpContext context)
        {
            string origin = context.Request.Headers["Origin"];
            if (!String.IsNullOrEmpty(origin))
                context.Response.AppendHeader("Access-Control-Allow-Origin", origin);
            else
                context.Response.AppendHeader("Access-Control-Allow-Origin", "*");
        }

        static void ClearResponse(HttpContext context)
        {
            context.Response.ClearHeaders();
            context.Response.ClearContent();
            context.Response.Clear();
        }

        public void Dispose()
        {
        }
    }

}

И в вашем web.config

<modules runAllManagedModulesForAllRequests="true">
    <add name="CrossOriginModule" preCondition="managedHandler" type="NAMESPACE.HttpModules.CrossOriginModule" />
</modules>

Это настроит заголовки ответа по мере необходимости и позволит MVC обработать запрос, как обычно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...