Опублікуйте дані в JsonP


102

Чи можна розміщувати дані на JsonP? Або всі дані повинні бути передані в рядку запитів як GET-запит?

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

Які існують варіанти подолання цього?

Відповіді:


83

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

Можна, звичайно, зробити сторінку на іншому домені дією звичайної форми POST.

Редагувати : Там є кілька цікавих хак , якщо ви готові докласти чимало зусиль, вставляючи приховані <iframe>s та розмовляючи зі своїми властивостями.


Ви згадали, що "асинхронний POST" неможливий .... то чи можу я зробити синхронний POST?
Марк

4
@mark "синхронний POST" означає подання форми, яка використовує <form method = "post" action = "http: // ... / ...">
Стівен Крискалла

8
Це не зовсім так. Ви, звичайно, можете робити POSTзапити в інші домени, якщо і цей домен, і ваша веб-переглядач CORS. Але цілком вірно це POSTі JSONPне сумісні.
hippietrail

2
JSONP реалізується шляхом вставки <script>тегів, які вказують на інший домен. Єдиний спосіб виконання POST-запитів у браузері - це через HTML форми або XMLHttpRequest.
фрідо

1
(загалом -) Можна (!) зробити асинхронний POST для послуги в іншому домені. обмеження на відповідь. обмеження також є на запит JSONP.
Рой Намір

20

Якщо вам потрібно надіслати багато даних міждоменним. Зазвичай я створюю послугу, яку можна зателефонувати за два етапи:

  1. Спочатку клієнт виконує форму подання (розміщення крос-домену). Служба зберігає вхід в сеанс на сервері (використовуючи GUID як ключ). (клієнт створює GUID і надсилає його як частину вводу)

  2. Тоді клієнт виконує звичайний введення сценарію (JSONP) як параметр, яким ви користуєтесь тим самим GUID, який ви використовували у публікації FORM. Сервіс обробляє вхід із сеансу та повертає дані у звичайному режимі JSONP. Після цього сеанс знищується.

Звичайно, це спирається на те, що ви пишете сервер-бекенд.


1
Спробував ваш підхід. Працював для FF14 та Chrome20. Opera11 і IE9 просто не перенесли цю посаду. (Перевірив це за допомогою інструментів налагодження та прослухав на сервері з іншого кінця) Можливо, пов’язане з інвалідністю IE саме це питання: stackoverflow.com/questions/10395803/… Скарга Chrome у консолі, але все ж таки POST: XMLHttpRequest не може load localhost: 8080 / xxx Null Origin null не дозволено Access-Control-Allow-Origin.
OneWorld

@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". Браузер отримує джерело сценарію за допомогою транзакції HTTP GET.

Тепер, якщо ваша служба JSONP знаходиться в тому ж домені, що і ваша сторінка для виклику, ви, ймовірно, можете щось обмотати разом із простим $.ajax()дзвінком. Якщо це не в одному домені, то я не впевнений, як це було б можливо.


У цьому випадку справа не в одному домені. І я припускаю, що можливий лише GET, але хотів перевірити, оскільки я тільки сьогодні почав читати про JsonP і мені потрібно прийняти деякі рішення щодо того, чи він підходить для того, що мені потрібно
ChrisCa

2
Якщо він не в одному домені, але він підтримує, CORSто це буде можливим, поки браузер його також підтримує. У цих випадках ви скористаєтеся звичайними, JSONа не простими JSONP.
hippietrail

Так, @hippietrail 2 роки має велику різницю :-) CORS, безумовно, робить це можливим, але, звичайно, це вимагає, щоб джерело даних було встановлено належним чином.
Pointy

0

Ви можете використовувати проксі-сервер CORS, використовуючи цей проект . Це спрямовуватиме весь трафік до кінцевої точки вашого домену та передаватиме цю інформацію на зовнішній домен. Оскільки браузер реєструє всі запити на один і той же домен, ми можемо розміщувати JSON. ПРИМІТКА. Це також працює з SSL-сертифікатами, що зберігаються на сервері.


-1

Є (хак) рішення, яке я робив це багато разів, ви зможете публікувати повідомлення з 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" );

json

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

Будь ласка, не те, що ви сервер більше не будете поважати SOP (таку ж політику походження), але кого це хвилює?


Це не AJAX з CORS. AJAX означає, що ви використовуєте XML. Це JSON [P] з CORS. JSONP - це "JSON" з "Padding". Якщо він надсилає дані JSON, завершені функцією виклику для підкладки, то це JSONP з CORS. Ви можете використовувати як позначення даних JSON, так і JSONP за межами просто введення <script>тегів у свій HTML DOM (чорт ви можете навіть використовувати їх у додатках для настільних ПК, скажімо, ви хотіли робити кілька запитів JSON на одному сервері та хотіли використовувати ім'я функції наприклад, ідентифікатор відстеження запиту).
BrainSlugs83

-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 відповідно до їх документації. api.jquery.com/jQuery.ajax
OneWorld
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.