Опубликовать данные в JsonP - PullRequest
101 голосов
/ 23 апреля 2010

Можно ли публиковать данные в JsonP? Или все данные должны быть переданы в строке запроса как запрос GET?

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

Какие есть способы обойти это?

Ответы [ 7 ]

81 голосов
/ 23 апреля 2010

Невозможно выполнить асинхронную POST для службы в другом домене из-за (вполне разумного) ограничения той же политики происхождения . JSON-P работает только потому, что вам разрешено вставлять теги <script> в DOM, и они могут указывать куда угодно.

Можно, конечно, сделать страницу на другом домене действием обычной формы POST.

Edit : Есть несколько интересных хаков , если вы готовы приложить немало усилий, вставив скрытые <iframe> s и копаясь в их свойствах.

20 голосов
/ 22 ноября 2010

Если вам нужно отправить много данных междоменных.Обычно я создаю службу, которую вы можете вызвать в два этапа:

  1. Сначала клиент отправляет FORM (пост разрешен для междоменного домена).Сервис сохраняет входные данные в сеансе на сервере (используя GUID в качестве ключа).(клиент создает GUID и отправляет его как часть ввода)

  2. Затем клиент выполняет обычный скрипт-инжект (JSONP) в качестве параметра, вы используете тот же GUID, что ииспользуется в ФОРМЕ пост.Служба обрабатывает входные данные из сеанса и возвращает данные в обычном JSONP-стиле.После этого сеанс уничтожается.

Это, конечно, зависит от того, что вы пишете серверную часть.

7 голосов
/ 05 июня 2014

Я знаю, что это серьезная некромантия, но я подумал, что опубликую свою реализацию JSONP POST с использованием jQuery, которую я успешно использую для своего виджета JS (это используется для регистрации клиентов и входа в систему):

По сути, я использую подход IFrame, как предлагается в принятом ответе. То, что я делаю по-другому, это то, что после отправки запроса я наблюдаю, можно ли получить форму в iframe, используя таймер. Когда форма не может быть достигнута, это означает, что запрос вернулся. Затем я использую обычный запрос JSONP для запроса статуса операции.

Я надеюсь, что кто-то найдет это полезным. Протестировано в> = IE8, Chrome, FireFox и Safari.

function JSONPPostForm(form, postUrl, queryStatusUrl, queryStatusSuccessFunc, queryStatusData)
{
    var tmpDiv = $('<div style="display: none;"></div>');
    form.parent().append(tmpDiv);
    var clonedForm = cloneForm(form);
    var iframe = createIFrameWithContent(tmpDiv, clonedForm);

    if (postUrl)
        clonedForm.attr('action', postUrl);

    var postToken = 'JSONPPOST_' + (new Date).getTime();
    clonedForm.attr('id', postToken);
    clonedForm.append('<input name="JSONPPOSTToken" value="'+postToken+'">');
    clonedForm.attr('id', postToken );
    clonedForm.submit();

    var timerId;
    var watchIFrameRedirectHelper = function()
    {
        if (watchIFrameRedirect(iframe, postToken ))
        {
            clearInterval(timerId);
            tmpDiv.remove();
            $.ajax({
                url:  queryStatusUrl,
                data: queryStatusData,
                dataType: "jsonp",
                type: "GET",
                success: queryStatusSuccessFunc
            });
        }
    }

    if (queryStatusUrl && queryStatusSuccessFunc)
        timerId = setInterval(watchIFrameRedirectHelper, 200);
}

function createIFrameWithContent(parent, content)
{
    var iframe = $('<iframe></iframe>');
    parent.append(iframe);

    if (!iframe.contents().find('body').length)
    {
        //For certain IE versions that do not create document content...
        var doc = iframe.contents().get()[0];
        doc.open();
        doc.close();
    }

    iframe.contents().find('body').append(content);
    return iframe;
}

function watchIFrameRedirect(iframe, formId)
{
    try
    {
        if (iframe.contents().find('form[id="' + formId + '"]').length)
            return false;
        else
            return true;
    }
    catch (err)
    {
        return true;
    }
    return false;
}

//This one clones only form, without other HTML markup
function cloneForm(form)
{
    var clonedForm = $('<form></form>');
    //Copy form attributes
    $.each(form.get()[0].attributes, function(i, attr)
    {
        clonedForm.attr(attr.name, attr.value);
    });
    form.find('input, select, textarea').each(function()
    {
        clonedForm.append($(this).clone());
    });

    return clonedForm;
}
4 голосов
/ 23 апреля 2010

В общем случае JSONP реализуется путем добавления тега <script> к вызывающему документу, так что URL-адрес службы JSONP является "src". Браузер выбирает источник скрипта с помощью транзакции HTTP GET.

Теперь, если ваша служба JSONP находится в том же домене, что и ваша вызывающая страница, вы, вероятно, можете что-то сделать вместе с простым вызовом $.ajax(). Если это не в том же домене, то я не уверен, как это было бы возможно.

0 голосов
/ 19 ноября 2015

Вы можете использовать CORS Proxy , используя этот проект .Он будет направлять весь трафик в конечную точку вашего домена и передавать эту информацию во внешний домен.Поскольку браузер регистрирует все запросы в одном домене, мы можем опубликовать JSON. ПРИМЕЧАНИЕ: Это также работает с SSL-сертификатами, хранящимися на сервере.

0 голосов
/ 29 апреля 2013

Есть (взломанное) решение, которое я делал много раз, вы сможете отправлять сообщения с JsonP. (Вы сможете опубликовать форму размером более 2000 символов, которую можете использовать в GET)

Клиентское приложение Javascript

$.ajax({
  type: "POST", // you request will be a post request
  data: postData, // javascript object with all my params
  url: COMAPIURL, // my backoffice comunication api url
  dataType: "jsonp", // datatype can be json or jsonp
  success: function(result){
    console.dir(result);
  }
});

JAVA

response.addHeader( "Access-Control-Allow-Origin", "*" ); // open your api to any client 
response.addHeader( "Access-Control-Allow-Methods", "POST" ); // a allow post
response.addHeader( "Access-Control-Max-Age", "1000" ); // time from request to response before timeout

PHP:

header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST');
header('Access-Control-Max-Age: 1000');

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

С помощью этого метода вы также можете изменить тип запроса с jsonp на json, оба работают, просто установите правильный тип содержимого ответа

JSONP

response.setContentType( "text/javascript; charset=utf-8" );

* 1028 JSON *

response.setContentType( "application/json; charset=utf-8" );

Обратите внимание, что ваш сервер больше не будет уважать SOP (та же политика происхождения), но кого это волнует?

0 голосов
/ 02 июня 2012

Возможно, вот мое решение:

В вашем JavaScript:

jQuery.post("url.php",data).complete(function(data) {
    eval(data.responseText.trim()); 
});
function handleRequest(data){
    ....
}

В вашем url.php:

echo "handleRequest(".$responseData.")";
...