Я установил веб-приложение ASP.NET, начиная с шаблона MVC 4 / Web API. Кажется, что все работает очень хорошо - никаких проблем, о которых я знаю. Я использовал Chrome и Firefox для просмотра сайта. Я тестировал с помощью Fiddler, и все отзывы, похоже, касаются денег.
Итак, я приступаю к написанию простого Test.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>
Это генерирует заголовок REQUEST:
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
Как есть, веб-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 по умолчанию не подключена к контроллерам веб-API ... Итак, я поместил следующий код в свой UserController.cs:
// OPTIONS http-verb handler
public HttpResponseMessage OptionsUser()
{
var response = new HttpResponseMessage();
response.StatusCode = HttpStatusCode.OK;
return response;
}
... и это устранило ошибку 405 Method Not Allowed, но ответ полностью пуст - данные не возвращаются:
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
Должна быть дополнительная логика ... Я не знаю, как правильно кодировать метод Options, или контроллер - это даже подходящее место для размещения кода. Странно (для меня), что сайт веб-API правильно реагирует при просмотре из Firefox или Chrome, но вызов .ajax выше вызывает ошибки. Как мне обработать "предполетную" проверку в коде .ajax? Может быть, мне следует решить эту проблему с помощью логики .ajax на стороне клиента? Или, если это проблема на стороне сервера из-за не обработки команды OPTIONS.
Кто-нибудь может помочь? Это должно быть очень распространенная проблема, и я прошу прощения, если здесь был дан ответ. Я искал, но не нашел ответов, которые помогли бы.
ОБНОВЛЕНИЕ IMHO, это проблема на стороне клиента и связана с приведенным выше кодом Ajax JQuery. Я говорю это потому, что Fiddler не показывает никаких заголовков ошибок 405, когда я обращаюсь к mywebapidomain / api / user из веб-браузера. Единственное место, где я могу воспроизвести эту проблему, - это вызов JQuery .ajax (). Кроме того, идентичный вызов Ajax, приведенный выше, отлично работает при запуске на сервере (в том же домене).
Я нашел еще одно сообщение: запрос прототипа AJAX отправляется как ОПЦИИ, а не GET; приводит к ошибке 501, которая кажется связанной, но я безуспешно возился с их предложениями. Судя по всему, JQuery закодирован так, что если запрос Ajax является кросс-доменом (каковым является мой), он добавляет пару заголовков, которые каким-то образом запускают заголовок OPTIONS.
'X-Requested-With': 'XMLHttpRequest',
'X-Prototype-Version': Prototype.Version,
Просто кажется, что должно быть лучшее решение, чем изменение основного кода в JQuery ...
В приведенном ниже ответе предполагается, что это проблема на стороне сервера. Может быть, я думаю, но я склоняюсь к клиенту, и звонок хостинг-провайдеру не поможет.
источник
Ответы:
Как сказал Дэниел А. Уайт в своем комментарии, запрос OPTIONS, скорее всего, создается клиентом как часть междоменного запроса JavaScript. Это делается автоматически браузерами, совместимыми с Cross Origin Resource Sharing (CORS). Запрос - это предварительный или предполетный запрос, сделанный перед фактическим запросом AJAX, чтобы определить, какие глаголы и заголовки запроса поддерживаются для CORS. Сервер может выбрать поддержку ни одного, всех или некоторых HTTP-глаголов.
Чтобы завершить картину, запрос AJAX имеет дополнительный заголовок «Origin», который определяет, откуда была обслужена исходная страница, на которой размещен JavaScript. Сервер может выбрать поддержку запроса из любого источника или только для набора известных надежных источников. Разрешение любого происхождения представляет собой угрозу безопасности, поскольку это может увеличить риск подделки межсайтовых запросов (CSRF).
Итак, вам нужно включить CORS.
Вот ссылка, объясняющая, как это сделать в веб-API ASP.Net.
http://www.asp.net/web-api/overview/security/enpting-cross-origin-requests-in-web-api#enable-cors
Описанная здесь реализация позволяет вам, среди прочего, указать
В общем, это работает нормально, но вам нужно убедиться, что вы осведомлены о рисках безопасности, особенно если вы разрешаете запросы с перекрестным происхождением из любого домена. Подумайте очень внимательно, прежде чем позволить это.
В отношении того, какие браузеры поддерживают CORS, Википедия сообщает, что следующие механизмы поддерживают его:
http://en.wikipedia.org/wiki/Cross-origin_resource_sharing#Browser_support
источник
Ответ Майка Гудвина великолепен, но когда я попробовал, мне показалось, что он нацелен на MVC5 / WebApi 2.1. Зависимости для Microsoft.AspNet.WebApi.Cors не очень хорошо работали с моим проектом MVC4.
Самый простой способ включить CORS в WebApi с MVC4 был следующим.
Обратите внимание, что я разрешил все, я предлагаю вам ограничить Origin только теми клиентами, которых вы хотите, чтобы ваш 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-глагол OPTIONS
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>
надеюсь это поможет
источник
Application_OnBeginRequest
мне помогло. Но если вы хотите , чтобы иметь возможность получить данные с разрешения тоже, вы должны также добавитьAuthorization
кAccess-Control-Allow-Headers
Столкнувшись с той же проблемой в проекте 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; } }
Для конфигурации веб-API:
config.MessageHandlers.Add(new AllowOptionsHandler());
Обратите внимание, что у меня также включены заголовки CORS в Web.config, аналогичные некоторым другим ответам, размещенным здесь:
<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, только с помощью специального кода в global.asax
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, содержащий несколько значений.
Также необходимо это в web.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>
А app.pool необходимо установить в интегрированный режим.
источник
У меня была такая же проблема. Для меня исправление заключалось в удалении настраиваемого типа контента из вызова jQuery AJAX. Пользовательские типы контента запускают предполетный запрос. Я нашел это:
На этой странице: http://www.asp.net/web-api/overview/security/enpting-cross-origin-requests-in-web-api (в разделе «Предварительные запросы»)
источник
В веб-API ASP.NET 2 добавлена поддержка CORS. Пожалуйста, проверьте ссылку [ http://www.asp.net/web-api/overview/security/enpting-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 на решение веб-API.
Затем добавьте файл CorsConfig в папку App_Start веб-API.
[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 во всех браузерах.
источник
У меня была такая же проблема, и вот как я ее исправил:
Просто добавьте это в свой web.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>
источник
//In the Application_OnBeginRequest method in GLOBAL.ASX add the following:- var res = HttpContext.Current.Response; var req = HttpContext.Current.Request; res.AppendHeader("Access-Control-Allow-Origin", "*"); res.AppendHeader("Access-Control-Allow-Credentials", "true"); res.AppendHeader("Access-Control-Allow-Headers", "Authorization"); 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(); } //Remove any entries in the custom headers as this will throw an error that there's to //many values in the header. <httpProtocol> <customHeaders> </customHeaders> </httpProtocol>
источник