Как обрабатывать метод "ОПЦИИ" в ASP.NET MVC
Приложение My Sencha Touch отправляет форму на мой asp.net-mvc-3 WebService, но вместо отправки POST
он отправляет OPTIONS
.
Я читаю подобный поток здесь, но я просто не знаю, как обрабатывать метод OPTIONS
в моем коде.
Я попытался добавить атрибут [AllowAjax]
к моему Action, но он, похоже, не существует в MVC3.
ОПЦИИ /GetInTouch/CommunicateCard HTTP/1.1
Хост: webservice.example.com
Referer: http://192.168.5.206/ Метод доступа-контроля-запроса: POST
Происхождение: http://192.168.5.206
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/534.24 (KHTML, например, Gecko) Chrome/11.0.696.71 Safari/534.24
Access-Control-Request-Headers: X-Requested-With, Content-Type
Принять:/
Accept-Encoding: gzip, deflate, sdch
Accept-язык: en-US, en; q = 0.8
Accept-Charset: ISO-8859-1, utf-8; q = 0,7, *; q = 0,3
В моем ActionMethod я использую следующий код.
public JsonpResult CommunicateCard(CommunicateCard communicateCard)
{
// Instantiate a new instance of MailMessage
MailMessage mMailMessage = new MailMessage();
// removed for security/brevity
// Set the body of the mail message
mMailMessage.Body = communicateCard.name; // THIS IS CURRENTLY BLANK :-(
// removed for security/brevity
mSmtpClient.Send(mMailMessage);
// do server side validation on form input
// if it valid return true
// else return false
// currently returning NULL cuz I don't care at this point.
return this.Jsonp(null);
}
Ответы
Ответ 1
Оказывается, мне нужно было создать ActionFilterAttribute
namespace WebService.Attributes
{
public class AllowCrossSiteJsonAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache);
HttpContext.Current.Response.Cache.SetNoStore();
filterContext.RequestContext.HttpContext.Response.AppendHeader("Access-Control-Allow-Origin", "*");
string rqstMethod = HttpContext.Current.Request.Headers["Access-Control-Request-Method"];
if (rqstMethod == "OPTIONS" || rqstMethod == "POST")
{
filterContext.RequestContext.HttpContext.Response.AppendHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
filterContext.RequestContext.HttpContext.Response.AppendHeader("Access-Control-Allow-Headers", "X-Requested-With, Accept, Access-Control-Allow-Origin, Content-Type");
}
base.OnActionExecuting(filterContext);
}
}
}
Ответ 2
Я решил это по-другому в MVC и IIS. Причина, по которой я нашел эту проблему, состояла в том, что я хотел получать данные POST с javascript на стороне клиента (для чего JSONP не работает), и, кроме того, он хотел разрешить данные JSON, которые находятся внутри содержимого запроса POST.
В действительности ваш код хочет игнорировать первый запрос CORS OPTIONS, поскольку это, скорее всего, будет "настройка на уровне сайта", а не на настройку вызова API.
Сначала я настроил IIS на отправку ответа CORS, это можно сделать через диспетчер IIS (или через обновления web.config), если вы используете IIS, затем перейдите на сайт, который вы хотите добавить эти два значения:
- Access-Control-Allow-Origin - "*" (для тестирования, для большей безопасности вы можете ограничить его до определенных доменов)
- Access-Control-Allow-Headers, "Content-Type, Accept" (это для публикации данных JSON)
Затем я создал специальный ActionFilter, который должен применяться для каждого контроллера, который вы хотите принять POST-данные, что может вызвать запрос CORS. Пользовательский фильтр действий:
public class CORSActionFilter : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.HttpContext.Request.HttpMethod == "OPTIONS")
{
// do nothing let IIS deal with reply!
filterContext.Result = new EmptyResult();
}
else
{
base.OnActionExecuting(filterContext);
}
}
}
Затем в начале каждого контроллера вам необходимо применить это для добавления в атрибут, например:
[CORSActionFilter]
public class DataSourcesController : Controller
Теперь я уверен, что есть способ сделать это во всем решении MVC (решения приветствуются), но нужно сделать барбекю и решение выше работает!
Ответ 3
Я добавил следующее в раздел <system.webServer>
config:
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Headers" value="Content-Type, Accept, X-Requested-With"/>
<add name="Access-Control-Allow-Methods" value="GET, POST, OPTIONS"/>
<add name="Access-Control-Allow-Origin" value="*"/>
</customHeaders>
</httpProtocol>
Ответ 4
Просто, чтобы ответить на вопрос, почему "ОПЦИИ", а не "POST", это потому, что браузер реализует CORS (Совместное использование ресурсов ресурса).
Это процесс, состоящий из двух частей отправки запроса OPTIONS, а затем, если сервер отвечает с приемлемыми условиями, браузер затем отправляет фактический запрос с данными/содержимым.
Ответ 5
Я попробовал все ответы здесь, и никто не работал. В конце концов я понял, что браузеры будут обрабатывать предполетную проверку как неудачную, если она вернет не 200. В моем случае IIS возвращал 404, даже с заголовками. Это связано с тем, что у меня было два атрибута для моего метода контроллера - [HttpPost] и [HttpOptions]. По-видимому, это не действительный механизм выражения нескольких глаголов. Я должен был использовать этот атрибут вместо: [AcceptVerbs (HttpVerbs.Options | HttpVerbs.Post)]