JsonP'ye veri gönderin


102

JsonP'ye veri göndermek mümkün mü? Yoksa tüm verilerin sorgu dizesinde bir GET isteği olarak iletilmesi mi gerekiyor?

Alanlar arası hizmete göndermem gereken çok sayıda veriye sahibim ve sorgu dizesi yoluyla göndermek için çok büyük

Bunu aşmak için seçenekler nelerdir?

Yanıtlar:


83

Aynı menşe politikasınınPOST (oldukça mantıklı) sınırlaması nedeniyle, başka bir etki alanındaki bir hizmete eşzamansız yapmak mümkün değildir . JSON-P yalnızca DOM'a etiket eklemenize izin verildiği için çalışır ve bunlar herhangi bir yere işaret edebilir.<script>

Elbette, başka bir etki alanındaki bir sayfayı normal bir POST formunun eylemi yapabilirsiniz.

Düzenleme : Gizli e-postaları yerleştirmek ve özellikleriyle uğraşmak için çok fazla çaba sarf etmeye istekliysen, orada bazı ilginç hackler var <iframe>.


"Eşzamansız POST" un mümkün olmadığından bahsettiniz .... o zaman eşzamanlı bir POST yapabilir miyim?
Mark

4
@mark "eşzamanlı POST" <form method = "post" action = "http: // ... / ..."> kullanan bir form göndermek anlamına gelir
Steven Kryskalla

8
Bu tam olarak doğru değil. POSTHem o etki alanı hem de tarayıcınız desteklediği sürece kesinlikle diğer etki alanlarına istek yapabilirsiniz CORS. Ancak bu tamamen doğrudur POSTve JSONPuyumlu değildir.
hippietrail

2
JSONP, <script>başka bir etki alanına işaret eden etiketler eklenerek uygulanır . Bir tarayıcıda POST isteklerini yürütmenin tek yolu HTML formları veya XMLHttpRequest yoluyladır.
friedo

1
(genel olarak -) Başka bir etki alanındaki bir hizmete zaman uyumsuz POST yapmak (!) mümkündür. sınırlama yanıt üzerindedir. sınırlama ayrıca JSONP isteği üzerinedir.
Royi Namir

20

Alanlar arası çok fazla veri göndermeniz gerekiyorsa. Genellikle iki adımda arayabileceğiniz bir servis oluşturuyorum:

  1. Önce müşteri bir FORM gönderimi yapar (izin verilen alanlar arası postayla). Hizmet, girişi sunucuda oturumda depolar (GUID'yi anahtar olarak kullanarak). (istemci bir GUID oluşturur ve bunu girdinin bir parçası olarak gönderir)

  2. Ardından istemci, FORM gönderisinde kullandığınız GUID'yi kullandığınız bir parametre olarak normal bir komut dosyası enjekte (JSONP) yapar. Hizmet, oturumdaki girdiyi işler ve verileri normal JSONP tarzında döndürür. Bundan sonra seans yok edilir.

Bu elbette sunucu arka ucunu yazmanıza bağlıdır.


1
Yaklaşımınızı denedim. FF14 ve Chrome20 için çalıştı. Opera11 ve IE9 sadece gönderiyi aktarmadı. (Hata ayıklama araçlarıyla kontrol ettiler ve diğer uçta sunucuda dinlediler) Belki de IE'nin engellenmesiyle ilgili olabilir : stackoverflow.com/questions/10395803/… Konsolda Chrome şikayeti var, ancak yine de POST yaptı: XMLHttpRequest load localhost: 8080 / xxx Origin null değerine Access-Control-Allow-Origin tarafından izin verilmiyor.
OneWorld

@OneWorld - Cevabın söylediğini yapmadın. XMLHttpRequesthiç karışmamalı. Per'in yanıtı, POST isteğini yapmak için normal bir form gönderimi, ardından GET isteğini yapmak için bir komut dosyası öğesi enjeksiyonu kullanır.
Quentin

7

Bunun ciddi bir necromancy olduğunu biliyorum, ancak JSONP POST uygulamamı JS widget'ım için başarıyla kullandığım jQuery'yi kullanarak göndereceğimi düşündüm (bu, müşteri kaydı ve oturum açma için kullanılır):

Temel olarak, kabul edilen cevapta önerildiği gibi bir IFrame yaklaşımı kullanıyorum. Farklı bir şekilde yaptığım şey ise isteği gönderdikten sonra, eğer forma iframe'de ulaşılabiliyorsa, zamanlayıcı kullanarak izliyorum. Forma ulaşılamaması, talebin geri döndüğü anlamına gelir. Ardından, işlemin durumunu sorgulamak için normal bir JSONP isteği kullanıyorum.

Umarım birisi onu yararlı bulur. > = IE8, Chrome, FireFox ve Safari'de test edilmiştir.

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

Genel olarak JSONP, <script>çağıran belgeye bir etiket eklenerek uygulanır , öyle ki JSONP hizmetinin URL'si "src" olur. Tarayıcı, komut dosyası kaynağını bir HTTP GET işlemi ile alır.

Şimdi, JSONP hizmetiniz çağrı sayfanızla aynı etki alanında ise, muhtemelen basit bir $.ajax()çağrı ile bir şeyi bir araya getirebilirsiniz . Aynı etki alanında değilse, nasıl mümkün olacağından emin değilim.


Bu durumda aynı etki alanında değildir. Ve sadece GET'in mümkün olduğunu varsayıyorum, ancak bugün JsonP hakkında okumaya başladığım ve ihtiyacım olan şey için uygun olup olmadığına dair bazı kararlar vermem gerektiği için kontrol etmek istedim
ChrisCa

2
Aynı etki alanında değilse ancak destekliyorsa CORS, tarayıcı da desteklediği sürece mümkün olacaktır. Bu durumlarda JSONyerine sade kullanacaksınız JSONP.
hippietrail

Evet, @hippietrail 2 yıl büyük bir fark yaratıyor :-) CORS kesinlikle bunu mümkün kılıyor, ancak elbette veri kaynağının uygun şekilde kurulmasını gerektiriyor.
Pointy

0

Bu projeyi kullanarak bir CORS Proxy kullanabilirsiniz . Tüm trafiği alanınızdaki bir uç noktaya yönlendirir ve bu bilgiyi harici bir alana aktarır. Tarayıcı aynı etki alanında olmak için tüm istekleri kaydettiğinden, JSON gönderebiliyoruz. NOT: Bu, sunucuda tutulan SSL sertifikalarıyla da çalışır.


-1

Birçok kez yaptığım bir (hack) çözümü var, JsonP ile gönderebileceksiniz. (GET ile kullanabileceğinizden 2000 karakterden büyük bir Form Gönderebileceksiniz)

İstemci uygulaması 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');

Böyle yaparak, sunucunuzu herhangi bir gönderi talebine açarsınız, bunu kimlik veya başka bir şey sağlayarak yeniden güvence altına almalısınız.

Bu yöntemle, istek türünü jsonp'den json'a da değiştirebilirsiniz, her ikisi de çalışır, sadece doğru yanıt içerik türünü ayarlayın

jsonp

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

json

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

Lütfen sunucunuzun artık SOP'ye (aynı menşe politikası) saygı göstermeyeceğini unutmayın, ama kimin umurunda?


Bu, CORS ile AJAX değildir. AJAX, XML kullandığınızı ima eder. Bu, CORS ile JSON [P]. JSONP, "Dolgu" ile "JSON" dur. Eğer doldurma için bir işlev çağrısıyla sarmalanmış JSON verisi gönderiyorsa, o zaman CORS ile JSONP'dir. <script>HTML DOM'nize etiket eklemenin dışında hem JSON hem de JSONP veri gösterimlerini kullanabilirsiniz (bunları bir masaüstü uygulamalarında bile kullanabilirsiniz, örneğin aynı sunucuya birden fazla JSON isteği yapmak istediğinizi ve işlev adını kullanmak istediğinizi varsayalım) örneğin bir istek izleme kimliği olarak).
BrainSlugs83

-6

Mümkün, işte benim çözümüm:

JavaScript'inizde:

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

Url.php'nizde:

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

11
Bu durumda jQuery, büyük olasılıkla isteğinizi belgelerine göre Al'a çevirdi: Not: Bu, uzak etki alanı istekleri için POST'ları GET'lere dönüştürecektir. api.jquery.com/jQuery.ajax
OneWorld
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.