Подтвердить что ты не робот

JQuery застрял в преддверии CORS и ответ призрака IIS

Я застрял. Серьезно... - . читайте дальше:)

Сценарий. Я пытаюсь сделать правильные вещи здесь. Я добавил функциональность CORS в свою службу REST (ASP.NET Web-API), опираясь на модель IdentityModel IdentityModel CORS DelegatingHandler. Пока все хорошо.

Чтобы проверить, работает ли он, я сделал следующее:

  • Я установил простую HTML-страницу и опубликовал ее на другом хосте, чем служба остального (xttp://otherhost/simplewebpage). На странице используется JQuery для запроса образца. Код см. Ниже.
  • Затем я настроил службу отдыха, чтобы не использовать iis express, а скорее полностью исполняемый экземпляр, запущенный на моей машине разработки (xttp://developmenthost/restservice).
  • Наконец, но не в последнюю очередь на моей машине разработки я открываю страницу xttp://otherhost/simplewebpage и запускаю запрос Ajax. Выполняется обратный вызов ошибки, говорящий, что в Chrome есть "транспортная ошибка" (IE9) или "" (пустая строка). Я убедился, что нет связи с подключением к прокси-серверу или что-то в этом роде.

Итак, я вышел и посмотрел следы Fiddler и журналы IIS. Скрипач говорит, что нет запроса GET/rest/hello, а скорее запроса OPTIONS/rest/hello, который полностью прекрасен и ожидается! Однако ответ на запрос OPTIONS довольно интригующий!

Весь заголовок ответа выглядит следующим образом:

HTTP/1.1 200 OK
Allow: OPTIONS, TRACE, GET, HEAD, POST
Server: Microsoft-IIS/7.5
Public: OPTIONS, TRACE, GET, HEAD, POST
Date: Fri, 15 Feb 2013 14:09:27 GMT
Content-Length: 0

Это, конечно, нигде даже близко к ожидаемому ответу. Интересная часть этого вопроса заключается в том, что запрос не попал даже в Application_BeginRequest() в моем приложении. Таким образом, мое приложение не может быть ответственным за этот результат. Я вижу запрос в моих журналах IIS, и IIS добавляет заголовок Powered-by-ASP.NET.. поэтому он определенно проходит через (правый) сайт IIS.

Код JQuery, который запускает запрос ajax:  

    function Run()
    {
        $.ajax({
            type: 'GET',
            url: url,
            dataType: "json",
            beforeSend: function(jqXhr) {
                jqXhr.setRequestHeader("Authorization", "Basic " + getBasicHttpEncodedString(userName, password));
                jqXhr.setRequestHeader("Api-Key", "123");
            },
            success: successCallback,
            error: errorCallback,
            timeout: 180*1000
        });
    }

Полученный запрос OPTIONS выглядит следующим образом:

OPTIONS http://services.dev13/Rest/Hello HTTP/1.1
Host: developmenthost
Connection: keep-alive
Access-Control-Request-Method: GET
Origin: http://otherhost/simplewebpage
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.57 Safari/537.17
Access-Control-Request-Headers: accept, origin, api-key, authorization
Accept: */*
DNT: 1
Referer: http://otherhost/simplewebpage
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3

... и вы уже видели ответ на это выше.

Любая идея, которая точно отвечает на мой запрос OPTIONS? Или мой код JQuery испорчен? Служба REST работает очень хорошо, если я использую, например, Postman (приложение Google Chrome) или если я создаю запросы в Fiddler (возможно, потому, что они не выполняют согласование CORS - там нет запроса OPTIONS).

Обновление # 1:. Сегодня я где-то читал, что отключение WebDAV является обязательным, поскольку оно мешает запросам OPTIONS. В представлении службы ролей IIS указано, что публикация WebDAV не установлена.

* Обновление # 2: * Проблема решена?? Я углубился. Там зарегистрирован модуль в IIS, который отвечает за "нежелательный (?)" Ответ на запрос OPTIONS. Его имя - "OPTIONSVerbHandler" (обработчик: ProtocolSupportModule). Если я отключу этот модуль, запрос будет передан в мое приложение. Там создается более значимый ответ, а затем выполняется фактический запрос GET! YAY!

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Expires: -1
Server: Microsoft-IIS/7.5
Access-Control-Allow-Origin: http://otherhost/simplewebpage
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: accept,origin,api-key,authorization
X-AspNet-Version: 4.0.30319
Date: Fri, 15 Feb 2013 15:09:25 GMT
Content-Length: 0

Как только вы узнаете, где проблема, конечно, вы найдете много ресурсов, говорящих вам убедиться, что ваш web.config выглядит так: -/

<system.webServer>
    <validation validateIntegratedModeConfiguration="false" />
    <modules runAllManagedModulesForAllRequests="false">
      <remove name="WebDAVModule" />
    </modules>
    <handlers>
      <remove name="OPTIONSVerbHandler" />
      <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>
  </system.webServer>

Он все еще не работает в IE9 ( "error: no transport" ). Если кто-то пошел по той же дороге, что и я, - это вещь IE9: qaru.site/info/49086/...

4b9b3361

Ответ 1

Ваш ответ здесь: https://gist.github.com/mathieucarbou/1114981

В принципе, IE имеет некоторые довольно конкретные оговорки и подводные камни для корса. Я начал писать один один раз, но потом нашел решение mathieucarbou и решил, что он лучше.

Это может быть немного более тяжелое решение, чем вы хотели, но для кросс-браузерной поддержки я нашел приемлемым, чтобы использовать IE с "настраиваемым решением" так сильно, как требуется.

Ответ 3

Создайте класс PreflightRequestsHandler, где вы разрешаете заголовки запросов (1) и разрешаете cors перед вашим классом (2).

1. public class PreflightRequestsHandler : DelegatingHandler
    {
        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            if (request.Headers.Contains("Origin") && request.Method.Method.Equals("OPTIONS"))
            {
                var response = new HttpResponseMessage { StatusCode = HttpStatusCode.OK };
                // Define and add values to variables: origins, headers, methods (can be global)               
                response.Headers.Add("Access-Control-Allow-Origin", "*");
                response.Headers.Add("Access-Control-Allow-Headers", "content-type");
                response.Headers.Add("Access-Control-Allow-Methods", "*");
                var tsc = new TaskCompletionSource<HttpResponseMessage>();
                tsc.SetResult(response);
                return tsc.Task;
            }
            return base.SendAsync(request, cancellationToken);
        }

    }

2. [EnableCors(origins: "*", headers: "*", methods: "*", exposedHeaders: "X-Custom-Header")]