Как загружать веб-ресурсы, такие как сценарии, изображения и т. д., из нужного места при добавлении поддержки CORS в веб-приложение?

У меня есть приложение asp.net mvc «App1», размещенное на моем локальном IIS, работающем на порту 1066, и другое приложение mvc «App2», размещенное и работающее на порту 1067.

Мое требование состоит в том, что App2 необходимо отправить некоторые данные в доступную конечную точку публикации App1, а App1 должно проверить эти данные. Если данные действительны, ответ будет иметь тип text/html, в противном случае будет получен неверный запрос, т. е. http statusCode 400.

Кроме того, оба приложения должны размещаться на разных доменах.

Чтобы создать прототип описанного выше случая, у меня есть скрытая форма в App2, и с помощью jquery я запускаю отправку этой формы, которая нацелена на имя iframe, например:

<form action="http://localhost:1066/user/index" method="POST" target="iframe" style="display: none;" id="mainForm">
    <input type="hidden" value="value1" name="h1" />
    <input type="hidden" value="value2" name="h2" />
    <input type="hidden" value="value3" name="h3" />
    <input type="submit" value="Submit" />
</form>

И javascript на той же странице:

$(document).ready(function() {

    $('body').append("<iframe id=\"iframe\" name=\"iframe\" style=\"width: 1200px; height: 1000px; border: none; margin: 0 auto; display: block;\"></iframe>");

    $("#mainForm").submit();

});

Приведенный выше код работает в соответствии с требованиями, то есть ответ от App1 отображается в iframe, и все ресурсы в этом ответе, такие как сценарии, изображения, css, шрифты, правильно загружаются в браузере.

Но чтобы прочитать код состояния http ответа, я не могу полагаться на обычную отправку формы. Итак, я решил использовать ajax для выполнения того же поста и изменил скрипт в App2, как показано ниже:

$(document).ready(function() {

  $('body').append("<iframe id=\"iembed\" name=\"iembed\" style=\"width: 1200px; height: 1000px; border: none; margin: 0 auto; display: block;\"></iframe>");

  var params = $('form').serialize();
            $.ajax({
                type: "POST",
                url: "http:// localhost:1066/user/index",
                data: params,
                crossDomain: true
            }).success(function (data, textStatus, jqXHR) {                
                $('#iframe').html(data);
            }).error(function () {
                alert("error");
            });

});

И чтобы включить междоменный запрос, хотя я нахожусь в своем локальном IIS, я добавил поддержку CORS, добавив следующее в файл web.config App1:

<httpProtocol>
  <customHeaders>
    <add name="Access-Control-Allow-Origin" value="*" />
    <add name="Access-Control-Allow-Headers" value="*" />
    <add name="Access-Control-Allow-Methods" value="POST, OPTIONS" />
  </customHeaders>
</httpProtocol>

Основываясь на моем понимании поддержки CORS, выполнение следующих изменений должно привести к получению такого же ответа, как если бы я выполнил обычную отправку формы выше.

Ответ отображается в iframe, но все ресурсы, такие как скрипты, css, изображения, шрифты из App1, загружаются неправильно. По какой-то причине, хотя App1 размещен на порту 1066, браузер ищет эти ресурсы в localhost:1067/Scripts/Vendor/respond.js?_=1406232120396. То же самое относится ко всем другим ресурсам, которые в представлении _Layout.cshtml моего App1 записываются с помощью @Url.Content("~/src"):

_Layout.cshtml в App1:

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>@ViewBag.Title</title>

    @Scripts.Render("~/bundles/modernizr")
    @Styles.Render("~/Content/css")


    <script src="@Url.Content("~/Scripts/Vendor/respond.js")"></script>
    <script src="@Url.Content("~/Scripts/Vendor/require.js")"></script>
</head>
<body>
    <img src="@Url.Content("~/Content/App/Images/abc.gif")" alt="Loading..." />
</body>

Изображение из fiddler, которое вы можете видеть ниже, говорит о том, что браузер ищет все сценарии и стили в файле макета выше в каталоге App2, а не загружает их из источника App1. Кроме того, запрос ресурсов /Content/css и /bundle/modernizr равен 200, поскольку в App2 определены пакеты с тем же именем. Ожидаемый результат: они должны быть загружены из localhost:1066//.

введите здесь описание изображения

Я не могу понять, почему это происходит только тогда, когда я делаю весь процесс через пост ajax. Поскольку тот же исходный код отлично работает при работе с обычной формой отправки без ajax.

  • Я что-то упустил для настройки в моем локальном IIS, из-за которого есть несоответствие указанных выше портов?
  • Или я что-то упустил, чтобы обеспечить полную поддержку CORS из приложения App1?
  • Или чего-то не хватает в запросе ajax в App2?
  • Или ожидается ли указанное выше поведение в среде разработки localhost при использовании ajax?

person Siddharth Pandey    schedule 24.07.2014    source источник


Ответы (1)


Ваша проблема на самом деле не имеет ничего общего с CORS. В вашем первом примере, когда вы отправляете POST на iframe, iframe фактически устанавливает его src на URL-адрес POST http://localhost:1066/user/index. Таким образом, ссылки на все ресурсы (изображения, скрипты и т. д.) относительны http://localhost:1066.

Во втором примере вы получаете тот же контент HTML, что и в первом примере, но поскольку вы просто вставляете его непосредственно в iframe, а не загружаете из http://localhost:1066, ссылки на ресурсы предназначены для http://localhost:1067. вместо.

Вы можете установить базовый путь, который используется для разрешения относительных путей, добавив <base>. В этом случае вы должны установить базу так же, как папка файла, в который вы отправлены в первом примере: <base href="http://localhost:1066/user/">

В MDN есть дополнительная информация об элементе <base>: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base?redirectlocale=en-US&redirectslug=HTML%2FElement%2Fbase

person pseudosavant    schedule 24.07.2014
comment
я добавил этот базовый тег в основной файл макета App1. однако при публикации в обычной форме src для iframe равен "". Даже после добавления базового тега изображение не загружается, оно по-прежнему загружается с порта 1067. Однако скрипты - requirejs, response.js загружаются из правильного места, но я получаю, что требование не определено, что раньше работало в обычной форме отправки. - person Siddharth Pandey; 25.07.2014
comment
@Yoda, можете ли вы предоставить дамп HTML, который находится в iframe после вашего вызова AJAX? - person pseudosavant; 25.07.2014
comment
Это ссылка на html, и я изменил свой Скрипт App2 для анализа html, как этот - person Siddharth Pandey; 25.07.2014
comment
Я посмотрю на это. К вашему сведению, я не думаю, что вы хотите так eval работать со своим JS. В конечном итоге javascript будет работать в неправильном контексте документа (родительский документ вместо iframe). Кроме того, использование eval для обработки ответов http (не https) представляет угрозу безопасности. - person pseudosavant; 25.07.2014
comment
хорошо, я удалю это. также из-за результата 404 для этого изображения ничего не добавляется в html iframe, не знаю почему !! Спасибо. Пожалуйста, дайте мне знать, если вы обнаружите в нем какую-либо проблему. - person Siddharth Pandey; 25.07.2014
comment
Посмотрите на этот jsbin, который я создал с фиктивной конечной точкой для извлечения HTML из другого домена: jsbin. com/qeyom/2/edit?js,output. Я могу установить <base>, и он правильно загружает изображение. Все ресурсы относительного пути в этом HTML должны загружаться с использованием этого базового href. - person pseudosavant; 25.07.2014
comment
Ваша демонстрация работает нормально, однако та же концепция не работает на двух моих локально размещенных сайтах. Я все еще пытаюсь решить эту проблему разными способами. - person Siddharth Pandey; 25.07.2014
comment
Я думаю, что ваш <base> неверен. В App1 index в URL-адресе http://localhost:1066/external/index есть папка или файл? Если это папка, то ваша база должна быть <base href="http://localhost:1066/external/index/" /> или если это файл, база должна быть <base href="http://localhost:1066/external/" />. В противном случае ваши относительные пути будут неверными. - person pseudosavant; 25.07.2014