Как поддержка HTTP-команду параметры в ASP.NET MVC-приложения/веб-API
Я настроил ASP.NET веб-приложение, начинающееся с шаблона MVC 4/Web API. Кажется, что все работает очень хорошо - никаких проблем, о которых я знаю. Я использовал Chrome и Firefox через сайт. Я проверил с помощью Fiddler и все ответы, кажется, на деньги.
Итак, теперь я приступаю к написанию простой тест.aspx для использования этого нового веб-API. Соответствующие части скрипта:
<script type="text/javascript">
$(function () {
$.ajax({
url: "http://mywebapidomain.com/api/user",
type: "GET",
contentType: "json",
success: function (data) {
$.each(data, function (index, item) {
....
});
}
);
},
failure: function (result) {
alert(result.d);
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
alert("An error occurred, please try again. " + textStatus);
}
});
});
</script>
это создает запрос заголовок:
OPTIONS http://host.mywebapidomain.com/api/user HTTP/1.1
Host: host.mywebapidomain.com
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:24.0) Gecko/20100101 Firefox/24.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Origin: http://mywebapidomain.com
Access-Control-Request-Method: GET
Access-Control-Request-Headers: content-type
Connection: keep-alive
как есть, Web API возвращает 405 метод не допускается.
HTTP/1.1 405 Method Not Allowed
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/xml; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Mon, 30 Sep 2013 13:28:12 GMT
Content-Length: 96
<Error><Message>The requested resource does not support http method 'OPTIONS'.</Message></Error>
Я понимаю, что глагол OPTIONS по умолчанию не подключен к контроллерам Web API... Итак, я разместил следующий код в моем UserController.cs:
// OPTIONS http-verb handler
public HttpResponseMessage OptionsUser()
{
var response = new HttpResponseMessage();
response.StatusCode = HttpStatusCode.OK;
return response;
}
...и это устранило 405 метод не допускается ошибка, но ответ полностью пуст - данные не возвращаются:
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Expires: -1
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Mon, 30 Sep 2013 12:56:21 GMT
Content-Length: 0
должна быть дополнительная логика... Я не знаю как правильно код метод опций или если контроллер даже является правильным местом для размещения кода. Странно (для меня), что сайт веб-API правильно реагирует при просмотре из Firefox или Chrome, но все же .ajax вызов выше ошибок. Как я могу справиться с" предполетной " проверкой .Аякс-код? Может быть, я должен решить эту проблему на стороне клиента .Аякс логика? Или, если это проблема на стороне сервера из-за НЕ обработки команды OPTIONS.
может кто-нибудь помочь? Это должна быть очень распространенная проблема, и я извинитесь, если вам ответили здесь. Я искал, но не нашел никаких ответов, которые помогли бы.
обновление IMHO, это проблема на стороне клиента и имеет отношение к коду Ajax JQuery выше. Я говорю это, потому что Fiddler не показывает никаких 405 заголовков ошибок при доступе к mywebapidomain/api/user из веб-браузера. Единственное место, где я могу дублировать эту проблему, - это JQuery .ajax () вызов. Кроме того, идентичный вызов Ajax выше отлично работает при запуске на сервере (то же самое домен.)
Я нашел еще один пост: прототип AJAX запрос отправляется как параметры, а не получить; результаты в 501 ошибка, которая, кажется, связана, но я возился с их предложениями без успеха. По-видимому, JQuery кодируется так, что если запрос Ajax является кросс-доменом (который мой), он добавляет пару заголовков, которые каким-то образом запускают заголовок OPTIONS.
'X-Requested-With': 'XMLHttpRequest',
'X-Prototype-Version': Prototype.Version,
просто кажется, что должно быть лучшее решение, чем изменение основного кода в JQuery...
ответ, приведенный ниже, предполагает, что это проблема на стороне сервера. Может быть, я думаю, но я склоняюсь к клиенту, и вызов хостинг-провайдера не поможет.
10 ответов:
Как сказал Даниэль А. Уайт в своем комментарии, запрос опций, скорее всего, создается клиентом как часть междоменного запроса JavaScript. Это делается автоматически совместимыми браузерами Cross Origin Resource Sharing (CORS). Запрос является предварительным или pre-flight запрос, сделанный до фактического запроса AJAX, чтобы определить, какие команды запроса и заголовки поддерживаются для CORS. Сервер может выбрать для поддержки его для none, all или некоторых HTTP глаголы.
чтобы завершить картину, запрос AJAX имеет дополнительный заголовок "Origin", который определяет, откуда была подана исходная страница, на которой размещен JavaScript. Сервер может выбрать поддержку запроса из любого источника или только для набора известных доверенных источников. Разрешение любого источника является угрозой безопасности, так как это может увеличить риск подделки межсайтовых запросов (CSRF).
Итак, вам нужно включить CORS.
вот ссылка, которая объясняет, как чтобы сделать это в ASP.Net Web API
http://www.asp.net/web-api/overview/security/enabling-cross-origin-requests-in-web-api#enable-cors
реализация, описанная там, позволяет вам указать, среди прочего
- поддержка CORS на основе каждого действия, каждого контроллера или глобальной базы
- поддерживаемые источники
- при включении базовых станций на контроллер или глобальном уровне, поддерживает протокол HTTP глаголы
- поддерживает ли сервер отправку учетных данных с запросами кросс-происхождения
В общем, это работает нормально, но вам нужно убедиться, что вы знаете о рисках безопасности, особенно если вы разрешаете перекрестные запросы происхождения из любого домена. Подумайте очень тщательно, прежде чем позволить это.
с точки зрения того, какие браузеры поддерживают CORS, Википедия говорит, что следующие движки поддерживают его:
- Gecko 1.9.1 (FireFox 3.5)
- WebKit (Safari 4, Chrome 3)
- MSHTML/Trident 6 (IE10) с частичной поддержкой в IE8 и 9
- Престо (Опера 12)
http://en.wikipedia.org/wiki/Cross-origin_resource_sharing#Browser_support
ответ Майка Гудвина велик, но мне показалось, когда я попробовал, что он был нацелен на MVC5/WebApi 2.1. Зависимости для Microsoft.сеть САШ.Веб-API.Корс не очень хорошо играл с моим проектом MVC4.
самый простой способ, чтобы включить CORS на веб-API с помощью MVC4 был следующим.
обратите внимание, что я разрешил все, я предлагаю вам ограничить происхождение только клиентов, которых вы хотите, чтобы ваш API служил. Разрешение всего-это безопасность риск.
Web.config:
<system.webServer> <httpProtocol> <customHeaders> <add name="Access-Control-Allow-Origin" value="*" /> <add name="Access-Control-Allow-Methods" value="GET, PUT, POST, DELETE, HEAD" /> <add name="Access-Control-Allow-Headers" value="Origin, X-Requested-With, Content-Type, Accept" /> </customHeaders> </httpProtocol> </system.webServer>
BaseApiController.cs:
мы делаем это, чтобы разрешить параметры http verb
public class BaseApiController : ApiController { public HttpResponseMessage Options() { return new HttpResponseMessage { StatusCode = HttpStatusCode.OK }; } }
просто добавьте это в ваш
Application_OnBeginRequest
метод (это позволит поддерживать CORS глобально для вашего приложения) и" обрабатывать " предполетные запросы:var res = HttpContext.Current.Response; var req = HttpContext.Current.Request; res.AppendHeader("Access-Control-Allow-Origin", req.Headers["Origin"]); res.AppendHeader("Access-Control-Allow-Credentials", "true"); res.AppendHeader("Access-Control-Allow-Headers", "Content-Type, X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Date, X-Api-Version, X-File-Name"); res.AppendHeader("Access-Control-Allow-Methods", "POST,GET,PUT,PATCH,DELETE,OPTIONS"); // ==== Respond to the OPTIONS verb ===== if (req.HttpMethod == "OPTIONS") { res.StatusCode = 200; res.End(); }
* безопасность: имейте в виду, что это позволит ajax-запросы из любого места на ваш сервер (вместо этого вы можете разрешить только разделенный запятыми список источников/URL-адресов, если вы предпочитаете).
я использовал текущее происхождение клиента вместо
*
потому что это позволит учетные данные => установкаAccess-Control-Allow-Credentials
в true позволит кросс-браузер управление сеансамитакже вам нужно включить удалить и поставить, патч и параметры глаголов в вашем
webconfig
разделsystem.webServer
, иначе IIS заблокирует их:<handlers> <remove name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" /> <remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" /> <remove name="ExtensionlessUrlHandler-Integrated-4.0" /> <add name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" /> <add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" /> <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" /> </handlers>
надеюсь, что это помогает
после того, как я столкнулся с той же проблемой в проекте Web API 2 (и не смог использовать стандартные пакеты CORS по причинам, не стоящим здесь), я смог решить эту проблему, реализовав пользовательский DelagatingHandler:
public class AllowOptionsHandler : DelegatingHandler { protected override async Task<HttpResponseMessage> SendAsync( HttpRequestMessage request, CancellationToken cancellationToken) { var response = await base.SendAsync(request, cancellationToken); if (request.Method == HttpMethod.Options && response.StatusCode == HttpStatusCode.MethodNotAllowed) { response = new HttpResponseMessage(HttpStatusCode.OK); } return response; } }
для конфигурации Web API:
config.MessageHandlers.Add(new AllowOptionsHandler());
обратите внимание, что у меня также есть заголовки CORS включены в Интернете.конфигурация, аналогичная некоторым другим ответам, опубликованным здесь:
<system.webServer> <modules runAllManagedModulesForAllRequests="true"> <remove name="WebDAVModule" /> </modules> <httpProtocol> <customHeaders> <add name="Access-Control-Allow-Origin" value="*" /> <add name="Access-Control-Allow-Headers" value="accept, cache-control, content-type, authorization" /> <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" /> </customHeaders> </httpProtocol> <handlers> <remove name="ExtensionlessUrlHandler-Integrated-4.0" /> <remove name="TRACEVerbHandler" /> <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" /> </handlers> </system.webServer>
обратите внимание, что мой проект не включает MVC, только Web API 2.
мне удалось преодолеть 405 и 404 ошибки, брошенные на предполетные запросы ajax options только по пользовательскому коду в global.асакс
protected void Application_BeginRequest() { HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*"); if (HttpContext.Current.Request.HttpMethod == "OPTIONS") { //These headers are handling the "pre-flight" OPTIONS call sent by the browser HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, OPTIONS"); HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept"); HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000"); HttpContext.Current.Response.End(); } }
PS: рассмотреть вопросы безопасности, когда позволяет все *.
мне пришлось отключить CORS, так как он возвращал заголовок "Access-Control-Allow-Origin", содержащий несколько значений.
также нужны в интернете.config:
<handlers> <remove name="ExtensionlessUrlHandler-Integrated-4.0"/> <remove name="OPTIONSVerbHandler"/> <remove name="TRACEVerbHandler"/> <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0"/> </handlers>
и приложения.пул должен быть установлен в интегрированный режим.
у меня была такая же проблема. Для меня исправление состояло в том, чтобы удалить пользовательский тип контента из вызова jQuery AJAX. Пользовательские типы контента инициируют запрос перед полетом. Я нашел это:
браузер может пропустить предварительный запрос, если выполняются следующие условия:
метод запроса
GET
,HEAD
илиPOST
,иприложение не устанавливает никаких заголовков запросов, кроме
Accept
,Accept-Language
,Content-Language
,Content-Type
илиLast-Event-ID
,иThe (если установлен) является одним из следующих:
application/x-www-form-urlencoded
multipart/form-data
text/plain
С этой страницы: http://www.asp.net/web-api/overview/security/enabling-cross-origin-requests-in-web-api (в разделе "предполетные запросы")
In ASP.NET добавлена поддержка web api 2, CORS . Пожалуйста, проверьте ссылку [ http://www.asp.net/web-api/overview/security/enabling-cross-origin-requests-in-web-api ]
protected void Application_EndRequest() { if (Context.Response.StatusCode == 405 && Context.Request.HttpMethod == "OPTIONS" ) { Response.Clear(); Response.StatusCode = 200; Response.End(); } }
Я тоже столкнулся с той же проблемой.
выполните следующий шаг, чтобы решить проблему соответствия (CORS) в браузерах.
включите REDRock в свое решение с помощью ссылки Cors. Включите ссылку WebActivatorEx на решение Web API.
затем добавьте файл CorsConfig в папку Web API App_Start.
[assembly: PreApplicationStartMethod(typeof(WebApiNamespace.CorsConfig), "PreStart")] namespace WebApiNamespace { public static class CorsConfig { public static void PreStart() { GlobalConfiguration.Configuration.MessageHandlers.Add(new RedRocket.WebApi.Cors.CorsHandler()); } } }
С этими изменениями я смог получить доступ к webapi во всех браузерах.
У меня была такая же проблема, и вот как я это исправил:
просто бросьте это в свою паутину.config:
<system.webServer> <modules> <remove name="WebDAVModule" /> </modules> <httpProtocol> <customHeaders> <add name="Access-Control-Expose-Headers " value="WWW-Authenticate"/> <add name="Access-Control-Allow-Origin" value="*" /> <add name="Access-Control-Allow-Methods" value="GET, POST, OPTIONS, PUT, PATCH, DELETE" /> <add name="Access-Control-Allow-Headers" value="accept, authorization, Content-Type" /> <remove name="X-Powered-By" /> </customHeaders> </httpProtocol> <handlers> <remove name="WebDAV" /> <remove name="ExtensionlessUrlHandler-Integrated-4.0" /> <remove name="TRACEVerbHandler" /> <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" /> </handlers> </system.webServer>