Опубликовать данные в JsonP

99

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

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

Каковы варианты обойти это?

Теги:
jsonp

7 ответов

85
Лучший ответ

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

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

Изменить. Есть несколько интересных хаков, если вы готовы пойти на большие усилия вставляя скрытые <iframe> и обманывая своими свойствами.

  • 0
    Вы упомянули, что "асинхронный POST" невозможен .... тогда я могу сделать синхронный POST?
  • 4
    @mark "синхронный POST" означает отправку формы, в которой используется <form method = "post" action = "http: // ... / ...">
Показать ещё 4 комментария
19

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

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

  • Затем клиент выполняет обычный script -inject (JSONP) в качестве параметра, который вы используете с тем же идентификатором GUID, который использовался в сообщении FORM. Служба обрабатывает ввод из сеанса и возвращает данные в обычном режиме JSONP. После этого сеанс уничтожается.

Это, конечно, полагается на то, что вы пишете сервер-сервер.

  • 1
    Попробовал твой подход. Работал на FF14 и Chrome20. Opera11 и IE9 просто не перенесли пост. (Проверил это с помощью своих инструментов отладки и прослушал на сервере на другом конце) Возможно, этот вопрос связан с инвалидностью IE: stackoverflow.com/questions/10395803/… Жалоба Chrome в консоли, но все-таки POST: XMLHttpRequest не может загрузить localhost: 8080 / xxx Исходное значение NULL не разрешено Access-Control-Allow-Origin.
  • 0
    @OneWorld - ты не сделал то, что сказал ответ. XMLHttpRequest не должен быть вовлечен вообще. Ответ Пера использует регулярную отправку формы для выполнения запроса POST, а затем внедрение элемента сценария для выполнения запроса GET.
7

Я знаю, что это серьезная некромантия, но я думал, что опубликую мою реализацию 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

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

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

  • 0
    Это не в том же домене в этом случае. И я предполагаю, что только GET возможен, но хотел проверить, поскольку я только начал читать о JsonP сегодня и должен принять некоторые решения о том, подходит ли он для того, что мне нужно
  • 2
    Если он не находится в том же домене, но поддерживает CORS то это будет возможно, если браузер также поддерживает его. В этих случаях вы будете использовать обычный JSON а не JSONP .
Показать ещё 1 комментарий
0

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

0

Там (взломать) решение я сделал это много раз, вы сможете отправлять сообщения с JsonP. (Вы сможете отправить форму, большую, чем 2000 char, чем вы можете использовать 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" );

JSON

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

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

  • 0
    Это не AJAX с CORS. AJAX подразумевает, что вы используете XML. Это JSON [P] с CORS. JSONP - это "JSON" с "Padding". Если он отправляет данные JSON, обернутые вызовом функции для заполнения, то это JSONP с CORS. Вы можете использовать нотации данных JSON и JSONP, не просто вставляя теги <script> в свою HTML DOM (черт возьми, вы даже можете использовать их в настольных приложениях, скажем, вы хотели сделать несколько запросов JSON на один и тот же сервер и хотели использовать имя функции в качестве идентификатора отслеживания запроса, например).
-6

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

В вашем javascript:

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

В вашем url.php:

echo "handleRequest(".$responseData.")";
  • 11
    В этом случае jQuery, скорее всего, превратил ваш запрос в Get согласно их документации: Примечание: это превратит POST в GET для запросов удаленного домена. api.jquery.com/jQuery.ajax

Ещё вопросы

Сообщество Overcoder
Наверх
Меню