Вопрос по jquery – Как сделать синхронный вызов между доменами JSONP

4

Я застрял с синхронным междоменным вызовом.

Ранее в моем приложении у нас был вызов домена, поэтому проблем не было

Мой предыдущий код JavaScript для совершения звонка был таким:

function EKXMLProvider(oDropdown, sDefault, sXML, sFilterUrl, fireRequestOnce)
{
    var oXMLHTTP, i, length, oData, sValue, sDisplay, sName, sMatch, oRegExp;

    if (!oDropdown)
        return;

    // XMLHTTP Object to retrieve the xml document
    oXMLHTTP = this.createXMLHttpRequest();
    this.FilterUrl = sFilterUrl;
    if (sFilterUrl != previousFilterUrl){
        oXMLHTTP.open("GET", sFilterUrl, false);
        oXMLHTTP.send(null);
        sFilterData = oXMLHTTP.responseText
        previousFilterUrl = sFilterUrl;
    }
    if(!fireRequestOnce ||(fireRequestOnce && retrievedData == null))
    {
        this.documentUrl = sXML;
        oXMLHTTP.open("GET", this.documentUrl, false);
        oXMLHTTP.send(null);

        oData = oXMLHTTP.responseXML.documentElement.childNodes;

        if(fireRequestOnce)
            retrievedData = oData;
    }
    else if(retrievedData != null)
    {
        oData = retrievedData;
    }
    this.suggestData = new Array();

    // Filter out all 2 and 3 letter codes (airport, city, country)
    oRegExp = new RegExp("\\s+\\(\\w{2,3}\\)", "gi");
    var iCount = 0    
    for (i = 0, length = oData.length; i < length; i++)
    {
        sValue = oData[i].attributes.getNamedItem("v").value;
        sDisplay = oData[i].attributes.getNamedItem("d").value;
        sName = oData[i].attributes.getNamedItem("n").value;
        //sMatch = oData[i].attributes.getNamedItem("m").value;
        sMatch = oData[i].attributes.getNamedItem("e").value;

        if (sFilterData.search(sValue) != -1){
            this.suggestData[iCount] = new EKSuggestData(sName + " (" + sValue + ")", sDisplay, sValue, sMatch, sMatch.replace(oRegExp, ""));
            iCount++;
        }
    }

    // Call the inherited class
    EKSuggestProvider.call(this, oDropdown, sDefault);
}

Теперь, когда мы переместили наши вызовы в другой домен, нам нужно совершать междоменные вызовы, я изменил приведенный выше код для междоменного домена, как показано ниже:

function EKXMLProvider(oDropdown, sDefault, sXML, sFilterUrl, fireRequestOnce)
{
    var oXMLHTTP, i, length, oData, sValue, sDisplay, sName, sMatch, oRegExp;
    var qr = "&jsonpcall=true";
    if (!oDropdown)
        return;

    // XMLHTTP Object to retrieve the xml document
    oXMLHTTP = this.createXMLHttpRequest();

    this.FilterUrl = sFilterUrl;

    if (sFilterUrl != previousFilterUrl){
    //alert(sFilterUrl);
        //oXMLHTTP.open("GET", sFilterUrl, false);
        //oXMLHTTP.send(null);
        //sFilterData = oXMLHTTP.responseText

        // queue up an ajax request
        $.ajax({
        url: sFilterUrl + qr,
        type: "GET",
        cache: true,
        async:false,
        contentType: "application/javascript; charset=utf-8",
        dataType: "jsonp",
        jsonpCallback: "airport", 
        success: function(data, textStatus, jqXHR) 
        {               
            if (data.airport[0] != '')
            {
                    sFilterData = data.airport[0];
            } 
        }
        });

        previousFilterUrl = sFilterUrl;        
    }

    if(!fireRequestOnce ||(fireRequestOnce && retrievedData == null))
    {
        //alert(sXML);
        this.documentUrl = sXML;
        //oXMLHTTP.open("GET", this.documentUrl, false);
        //oXMLHTTP.send(null);

        // queue up an ajax request
          $.ajax({
            url: sXML + qr,
            type: "GET",
            async:false,
            cache: true,
            contentType: "application/javascript; charset=utf-8",
            dataType: "jsonp",
            jsonpCallback: "airportxml", 
            success: function(data, textStatus, jqXHR) 
            {                 
                  var xmlDoc = $.parseXML(data.myresult);
                oData = xmlDoc.documentElement.childNodes; 
                alert(oData);
            }
            });

        //oData = oXMLHTTP.responseXML.documentElement.childNodes;

         if(fireRequestOnce)
             retrievedData = oData;
    }
    else if(retrievedData != null)
    {
        oData = retrievedData;
    }
    this.suggestData = new Array();

      // Filter out all 2 and 3 letter codes (airport, city, country)
      oRegExp = new RegExp("\\s+\\(\\w{2,3}\\)", "gi");
      var iCount = 0    
    for (i = 0, length = oData.length; i < length; i++)
    {
        sValue = oData[i].attributes.getNamedItem("v").value;
        sDisplay = oData[i].attributes.getNamedItem("d").value;
        sName = oData[i].attributes.getNamedItem("n").value;
        //sMatch = oData[i].attributes.getNamedItem("m").value;
        sMatch = oData[i].attributes.getNamedItem("e").value;

          if (sFilterData.search(sValue) != -1){
            this.suggestData[iCount] = new EKSuggestData(sName + " (" + sValue + ")", sDisplay, sValue, sMatch, sMatch.replace(oRegExp, ""));
            iCount++;
        }
    }

    // Call the inherited class
    EKSuggestProvider.call(this, oDropdown, sDefault);
}

Выше Jquery изменения работают нормально, когда я помещаю & quot; async: false, & quot; однако в моем вызове, насколько мне известно, у нас не может быть синхронного вызова в междоменной области, и если я изменю на «async: true», quot; звонок начинает выдавать ошибку на линии( for (i = 0, length = oData.length; i < length; i++)) поскольку данные должны быть заполнены во втором «airportxml» и кажется, что оба вызова зависят друг от друга, поэтому, когда отправляется первый вызов, он одновременно переходит и к следующему вызову.

Я также использовал ajaxQueue, но не повезло.

Пожалуйста, предложите, какие изменения мне нужно сделать.

@Esailija, не могли бы вы прояснить это подробнее, любой пример ссылки или кода Manoj Singh
Вы можете переместить этот код в функцию обратного вызова. Ваш конструктор выполняет слишком много реальной работы, он должен просто создать и инициализировать объект Esailija

Ваш Ответ

3   ответа
5

Как объясняется zi42, иjQuery.ajax() documentation, & quot; междоменных запросов иdataType: "jsonp" запросы не поддерживают синхронную работу. & apos;

Это неплохо, учитывая, что синхронный вызов имеет тенденцию приводить к ухудшению взаимодействия с пользователем, поскольку он блокирует браузер до тех пор, пока ответ не возвращается, поэтому я буду избегать выполнения синхронного вызова даже со стандартным Ajax там, где он есть. легко реализовать. Вы хотите сделать два синхронных вызова подряд, чтобы было еще хуже.

Обходной путь zi42, предложенный в комментарии - синхронный вызов Ajax на ваш собственный домен и затем междоменный вызов с вашего сервера - это лучший подход, который вы могли бы использовать, если вы действительно хотите, чтобы он был синхронным.

Другой очевидный подход - это реструктурировать ваш код так, чтобы он работал асинхронно, помещая то, что вы хотите делать после каждого запроса jsonp, в обратный вызов успеха. То есть при обратном вызове успеха первого запроса jsonp вы продолжаете делать второй запрос jsonp. В течение второго обратного вызова вы выполняете окончательную обработку. Если вам нужно передать окончательные результаты в другую часть кода, поместите код Ajax в функцию, которая принимает обратный вызов в качестве параметра:

function doMyAjaxCalls(callbackFunc) {
   // make first request
   $.ajax({
      ...
      dataType: "jsonp",
      success: function(data, textStatus, jqXHR) {
         // do something with first response, then
         // make second request              
         $.ajax({
            ...
            dataType: "jsonp",
            success: function(data, textStatus, jqXHR) {
               // do something with second response, then
               // do final processing, then
               callbackFunc(dataHere);
            }
         });
      }
   });
}

doMyAjaxCalls(function(response) {
   // do something with response
});
@sarojanand - URL может быть любым. У ОП было два разных URL.
Какой будет URL для обоих вызовов ajax? это будет тот же URL? Если да, не будет ли в этом случае вызывать одни и те же данные дважды?
0

Другой вариант - заблокировать пользовательский интерфейс (не блокировать выполнение).

Используйте что-то вродеBlockUI это будет "серым" экран, пока ваш звонок не закончится.

3

Когда вы используете JSONP, запрос выполняется не через XHR, а путем добавления фактического<script> тег к DOM. Вот почему вы не можете сделать это синхронно. Это просто невозможно.

Незначительная коррекция опечатки: jsonp не может бытьsynchronous.
Спасибо, я сделал исправление :)
Какой еще вариант можно реализовать с помощью jquery или чего-то еще? Manoj Singh
Единственный вариант - иметь «прокси» сценария на том же домене и передавая ему URL, который вы хотите получить. Скажи, что твой javascript включенdomain1.com и вы хотите сделать запрос AJAX дляhttp://domain2.com/some_resource, то вы бы сделать запрос AJAX кhttp://domain1.com/domain2_proxy.php, В domain2_proxy.php вы должны сделать запрос cURL к фактическому URL, передав любой параметр, который был передан вам в$_GET, Тогда вы бы вернули форму ответа cURL.
@ zi42, у меня не может быть реализации типа вызова через прокси-сервер, как будто я снова собираюсь вызвать domain1 для чего нужен прямой вызов между доменами, я хочу что-то вроде вышеупомянутой имплементации ... пожалуйста, предложите, так как это действительно для меня боль Manoj Singh

Похожие вопросы