Używanie PUT / POST/DELETE z JSONP i jQuery

Pracuję nad stworzeniem RESTful API, które obsługuje żądania między domenami, obsługę JSON/JSONP i główną metodę HTTP (PUT/GET/POST / DELETE). Teraz, podczas gdy będzie łatwy dostęp do tego API poprzez kod po stronie serwera, miło byłoby wystawić go na javascript. Z tego, co mogę powiedzieć, podczas wykonywania żądań JSONP z jQuery, obsługuje tylko metodę GET. Czy istnieje sposób na wykonanie żądania JSONP za pomocą POST/PUT / DELETE?

Najlepiej jak bym chciał to zrobić z poziomu jQuery (za pośrednictwem wtyczki, jeśli rdzeń nie obsługuje tego), ale wezmę też proste rozwiązanie javascript. Wszelkie linki do działającego kodu lub jak go kodować będą pomocne, dzięki.

Author: ryanzec, 2011-03-18

4 answers

Właściwie - istnieje sposób na obsługę żądań POST. I nie ma potrzeby w serwerze PROXI-wystarczy mała użyteczna strona HTML, która jest opisana poniżej.

Oto jak skutecznie uzyskać połączenie między domenami, w tym załączone pliki i wieloczęściowe i wszystkie:)]}

Tutaj najpierw są kroki w zrozumienia pomysł, następnie-znaleźć próbkę implementacji.

Jak zaimplementowany jest JSONP z jQuery i dlaczego nie obsługuje POST prośby?

Podczas gdy tradycyjny JSONP jest zaimplementowany przez utworzenie elementu skryptu i dodanie go do DOM - co powoduje, że przeglądarka uruchamia żądanie HTTP w celu pobrania źródła znacznika, a następnie uruchamia je jako JavaScript, żądanie HTTP, które wywołuje przeglądarka, jest proste GET.

Co nie ogranicza się do żądania?

FORMULARZ. Wyślij formularz podczas określania action serwera między domenami. Można utworzyć znacznik formularza całkowicie za pomocą skryptu, wypełniony wszystkimi polami za pomocą skryptu, ustaw wszystkie niezbędne atrybuty, wstrzyknięty do DOM, a następnie przesłany-wszystko za pomocą skryptu.

Ale jak możemy przesłać formularz bez odświeżania strony?

Określamy target formularz do ramki IFRAME na tej samej stronie. Ramka IFRAME może być również utworzona, ustawiona, nazwana i wstrzyknięta do DOM za pomocą skryptu.

Ale jak możemy ukryć tę pracę przed użytkownikiem? Będziemy zawierać zarówno formę jak i IFRAME w ukrytym DIV używając style="display:none"

W tym celu należy wykonać kilka czynności.]}

Ale IFRAME z innej domeny nie może wywołać połączenia zwrotnego na dokumencie najwyższego poziomu. Jak to przezwyciężyć?

Rzeczywiście, jeśli odpowiedź z formularza submit jest stroną z innej domeny, każda komunikacja skryptowa między stroną najwyższego poziomu a stroną w ramce IFRAME skutkuje "odmową dostępu". Więc serwer nie może oddzwaniać za pomocą skryptu. Co może serwer może zrobić? redirect . Serwer może przekierować na dowolną stronę-w tym strony w tej samej domenie co dokument najwyższego poziomu-strony, które mogą wywołać callback dla nas.

Jak serwer może przekierować?

Dwa sposoby:

  1. używanie skryptu po stronie klienta jak <Script>location.href = 'some-url'</script>
  2. używanie nagłówka HTTP. Zobacz: http://www.webconfs.com/how-to-redirect-a-webpage.php

Więc skończę z inną stroną? Jak to pomaga ja?

Jest to prosta strona narzędziowa, która będzie używana ze wszystkich wywołań między domenami. W rzeczywistości ta strona jest rodzajem proxi, ale nie jest to serwer, ale prosta i statyczna strona HTML , z której może korzystać każdy, kto ma notatnik i przeglądarkę.

Wszystko, co ta strona musi zrobić, to wywołać callback na dokumencie najwyższego poziomu, z danymi odpowiedzi z serwera. Skrypty po stronie klienta mają dostęp do wszystkich części URL, a serwer może umieścić tam swoją odpowiedź zakodowaną jako jego część, a także nazwę wywołania zwrotnego, które ma być wywołane. Oznacza-ta strona może być statyczna i HTML, i nie musi być dynamiczną stroną po stronie serwera:)

Ta strona narzędzia pobierze informacje z adresu URL, w którym działa - konkretnie w mojej implementacji poniżej-parametry query-String (lub możesz napisać własną implementację za pomocą Anchor-ID-i. e część adresu URL bezpośrednio do znaku"#"). A ponieważ ta strona jest statyczna - można nawet pozwolić na cached :)

Czy dodanie do każdego postu nie spowoduje w końcu wycieku pamięci DIV, skryptu i IFRAME?

Jeśli zostawisz go na stronie-będzie. Jeśli sprzątasz po sobie - nie będzie. Wszystko co musimy zrobić to dać ID do DIV, który możemy użyć do celan-up DIV I formularz i IFRAME wewnątrz niego, gdy odpowiedź przychodzi z serwera, lub times out.

Co dostaniemy?

Skutecznie wywołanie międzyzakładowe, w tym Dołączone pliki i wieloczęściowe i wszystkie :)

Jakie są limity?

    Odpowiedź serwera jest ograniczona do tego, co pasuje do przekierowania.
  • serwer musi zawsze zwracać przekierowanie do żądań POST. Które zawierają błędy 404 i 500. Alternatywnie-Utwórz limit czasu na kliencie tuż przed uruchomieniem żądania, abyś miał szansę wykryć żądania, które nie powróciły.
  • nie każdy może zrozumieć to wszystko i wszystkie etapy zaangażowany. jest to rodzaj pracy na poziomie infrastruktury, ale gdy już ją uruchomisz-wymiata:) [61]}

Czy mogę go używać do wysyłania i usuwania połączeń?

Znacznik formularza nie umieszcza i nie usuwa. Ale to lepiej niż nic :)

Ok, mam pomysł. Jak to technicznie jest zrobione?

To co robię to:

Tworzę DIV, stylizuję go jako niewidzialny i dołączam do DOM. Daję mu również identyfikator, że mogę go wyczyścić z DOM po nadeszła odpowiedź serwera (tak samo jak jQuery czyści to skrypt JSONP-ale DIV).

Następnie ja komponuję łańcuch zawierający zarówno IFRAME, jak i FORM - ze wszystkimi atrybutami, właściwościami i polami wejściowymi, i wprowadzam go do niewidzialnego DIV. ważne jest, aby wprowadzić ten łańcuch do DIV dopiero po tym, jak div znajduje się w DOM. jeśli nie-nie będzie działać na wszystkich przeglądarkach.

Po tym-uzyskuję odniesienie do formularza i składam go. Tylko pamiętaj jedna linia wcześniej-aby ustawić Timeout callback na wypadek, gdyby serwer nie odpowiedział Lub odpowiedział w niewłaściwy sposób.

Funkcja wywołania zwrotnego zawiera kod czyszczenia. Jest również wywoływany przez timer w przypadku odpowiedzi-timeout(i czyści to timeout-timer, gdy nadejdzie odpowiedź serwera).

Pokaż mi kod!

Poniższy fragment kodu jest całkowicie "neutralny" dla "czystego" javascript i deklaruje dowolne narzędzie, którego potrzebuje. Tylko dla uproszczenia wyjaśnianie idei-to wszystko działa na skalę globalną, jednak powinno być trochę bardziej wyrafinowane...

Zorganizuj go w funkcje, jak możesz i sparametryzuj to, czego potrzebujesz - ale upewnij się, że wszystkie części, które muszą się widzieć, działają na tym samym zakresie:)

Dla tego przykładu-załóżmy, że klient działa na http://samedomain.com a serwer działa na http://crossdomain.com .

Kod skryptu na najwyższym poziomie dokument

//declare the Async-call callback function on the global scope
function myAsyncJSONPCallback(data){
    //clean up 
    var e = document.getElementById(id);
    if (e) e.parentNode.removeChild(e);
    clearTimeout(timeout);

    if (data && data.error){
        //handle errors & TIMEOUTS
        //...
        return;
    }

    //use data
    //...
}

var serverUrl          = "http://crossdomain.com/server/page"
  , params = { param1  : "value of param 1"      //I assume this value to be passed
             , param2  : "value of param 2"      //here I just declare it...
             , callback: "myAsyncJSONPCallback" 
             }
  , clientUtilityUrl   = "http://samedomain.com/utils/postResponse.html"
  , id     = "some-unique-id"// unique Request ID. You can generate it your own way
  , div    = document.createElement("DIV")       //this is where the actual work start!
  , HTML   = [ "<IFRAME name='ifr_",id,"'></IFRAME>"  
             , "<form target='ifr_",id,"' method='POST' action='",serverUrl 
             , "' id='frm_",id,"' enctype='multipart/form-data'>"
             ]
  , each, pval, timeout;

//augment utility func to make the array a "StringBuffer" - see usage bellow
HTML.add = function(){
              for (var i =0; i < arguments.length; i++) 
                  this[this.length] = arguments[i];
           }

//add rurl to the params object - part of infrastructure work
params.rurl = clientUtilityUrl //ABSOLUTE URL to the utility page must be on
                               //the SAME DOMAIN as page that makes the request

//add all params to composed string of FORM and IFRAME inside the FORM tag  
for(each in params){
    pval = params[each].toString().replace(/\"/g,"&quot;");//assure: that " mark will not break
    HTML.add("<input name='",each,"' value='",pval,"'/>"); //        the composed string      
}
//close FORM tag in composed string and put all parts together
HTML.add("</form>");
HTML = HTML.join("");   //Now the composed HTML string ready :)

//prepare the DIV
div.id = id; // this ID is used to clean-up once the response has come, or timeout is detected
div.style.display = "none"; //assure the DIV will not influence UI

//TRICKY: append the DIV to the DOM and *ONLY THEN* inject the HTML in it
//        for some reason it works in all browsers only this way. Injecting the DIV as part 
//        of a composed string did not always work for me
document.body.appendChild(div);
div.innerHTML = HTML;

//TRICKY: note that myAsyncJSONPCallback must see the 'timeout' variable
timeout = setTimeout("myAsyncJSONPCallback({error:'TIMEOUT'})",4000);
document.getElementById("frm_"+id+).submit();

Serwer na cross-domenie Oczekuje się, że odpowiedź z serwera będzie przekierowaniem, albo przez nagłówek HTTP, albo przez napisanie znacznika skryptu. (przekierowanie jest lepsze, znacznik skryptu jest łatwiejszy do debugowania za pomocą punktów przerwania JS). Oto przykład nagłówka, przyjmując wartość {[8] } z góry

Location: http://samedomain.com/HTML/page?callback=myAsyncJSONPCallback&data=whatever_the_server_has_to_return

Zauważ, że

  • wartość argumentu data może być obiektem JavaScript-dosłownym lub wyrażeniem JSON, jednak lepiej być kodowany url.
  • długość odpowiedzi serwera jest ograniczona do długości adresu URL, który przeglądarka może przetworzyć.

Również-w moim systemie serwer ma domyślną wartość rurl, więc parametr ten jest opcjonalny. Ale możesz to zrobić tylko wtedy, gdy Twoja aplikacja klient i aplikacja Serwer są połączone.

API do emitowania nagłówka przekierowania:

Http://www.webconfs.com/how-to-redirect-a-webpage.php

Alternatywnie, możesz mieć serwer napisz jako odpowiedź:

<script>
   location.href="http://samedomain.com/HTML/page?callback=myAsyncJSONPCallback&data=whatever_the_server_has_to_return"
</script>

Ale HTTP-Headery byłyby uważane za bardziej czyste ;)

Strona narzędzia w tej samej domenie co dokument najwyższego poziomu

Używam tej samej strony narzędzia, co rurl dla wszystkich moich żądań postu: wszystko, co robi, to bierze nazwę wywołania zwrotnego i parametry z łańcucha zapytania za pomocą kodu po stronie klienta i wywołuje go w dokumencie nadrzędnym. Może to zrobić TYLKO , gdy ta strona działa w dokładnie tej samej domenie jako strona, która wystrzeliła żądanie! Ważne: w przeciwieństwie do ciasteczek - subdomeny się nie liczą!! To musi być dokładnie ta sama dziedzina.

Jest to również bardziej efektywne, jeśli ta strona narzędzia nie zawiera odniesień do innych zasobów -w tym bibliotek JS. Więc ta strona jest zwykły JavaScript. Ale możesz go wdrożyć, jak chcesz.

Oto strona odpowiedzi, której używam, której adres URL znajduje się w rurl żądania POST (w przykładzie: http://samedomain.com/utils/postResponse.html )

<html><head>
<script type="text/javascript">
//parse and organize all QS parameters in a more comfortable way
var params = {};
if (location.search.length > 1) {
    var i, arr = location.search.substr(1).split("&");
    for (i = 0; i < arr.length; i++) {
        arr[i] = arr[i].split("=");
        params[arr[i][0]] = unescape(arr[i][1]);
    }
}

//support server answer as JavaScript Object-Literals or JSON:
//  evaluate the data expression
try { 
    eval("params.data = " + params.data); 
} catch (e) { 
    params.data = {error: "server response failed with evaluation error: " + e.message
                  ,data : params.data
                  }
}

//invoke the callback on the parent
try{
     window.parent[ params.callback ](params.data || "no-data-returned");
}catch(e){
     //if something went wrong - at least let's learn about it in the
     //      console (in addition to the timeout)
     throw "Problem in passing POST response to host page: \n\n" + e.message;
}
</script>
</head><body></body></html>

To nie jest zbyt dużo automatyzacji i 'gotowej' biblioteki jak jQuery i wymaga jakiejś 'ręcznej' pracy-ale ma urok:)

Jeśli jesteś zapalonym fanem gotowych bibliotek - możesz również sprawdzić na Dojo Toolkit że kiedy ostatnio sprawdzałem (około rok temu) - miały własną implementację dla tego samego mechanizmu. http://dojotoolkit.org/

Powodzenia kolego, mam nadzieję, że to pomoże...

 70
Author: Radagast the Brown,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-11 23:04:21

Czy istnieje sposób na wykonanie żądania JSONP za pomocą POST/PUT / DELETE?

Nie ma.

 12
Author: Darin Dimitrov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-17 21:31:05

Nie. Zastanów się, czym jest JSONP: wstrzyknięcie nowego znacznika <script> w dokumencie. Przeglądarka wykonuje GET żądanie, aby pobrać skrypt wskazywany przez atrybut src. Nie ma sposobu, aby określić inny czasownik HTTP podczas robienia tego.

 8
Author: Wayne Burkett,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-17 21:37:30
  • zamiast walić w głowę metodą JSONP, to faktycznie nie wsparcie metody POST domyślnie możemy przejść do CORS .To nie przyniesie dużych zmian w konwencjonalnym sposobie programowania. Poprzez proste wywołanie Jquery Ajax możemy przejść z cross domen.
  • w metodzie CORS, musisz dodać nagłówki w pliku skryptowym po stronie serwera lub w samym serwerze (w domenie zdalnej), aby umożliwić ten dostęp. Jest to bardzo wiarygodne, ponieważ możemy zapobiec / ograniczyć tworzenie domen niechciane rozmowy.
  • można go znaleźć szczegółowo na stroniewikipedia .
 2
Author: Ganesh Babu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-23 10:25:13