Verwenden von PUT/POST/DELETE mit JSONP und jQuery

Lesezeit: 13 Minuten

Ich arbeite daran, eine RESTful-API zu erstellen, die domänenübergreifende Anfragen, JSON/JSONP-Unterstützung und die HTTP-Hauptmethode (PUT/GET/POST/DELETE) unterstützt. Während der Zugriff auf diese API über den serverseitigen Code jetzt einfach sein wird, wäre es schön, sie Javascript zugänglich zu machen. Soweit ich das beurteilen kann, unterstützt es bei JSONP-Anfragen mit jQuery nur die GET-Methode. Gibt es eine Möglichkeit, eine JSONP-Anfrage mit POST/PUT/DELETE durchzuführen?

Idealerweise hätte ich gerne eine Möglichkeit, dies von jQuery aus zu tun (über ein Plugin, wenn der Kern dies nicht unterstützt), aber ich nehme auch eine einfache JavaScript-Lösung. Alle Links zu funktionierendem Code oder wie man ihn codiert, wäre hilfreich, danke.

  • Überprüfen Sie die Antwort, die ich unten gegeben habe. Es ist ziemlich lang – aber es enthält alles, was Sie wissen müssen, um zu verstehen, wie es gemacht wird – von der Ebene des Konzepts bis hin zur unteren Ebene.

    – Radagast der Braune

    19. März ’11 um 8:30

Verwenden von PUTPOSTDELETE mit JSONP und jQuery
Radagast der Braune

Tatsächlich gibt es eine Möglichkeit, POST-Anfragen zu unterstützen. Und in einem PROXI-Server besteht keine Notwendigkeit – nur eine kleine Utility-HTML-Seite, die unten beschrieben wird.

So erhalten Sie effektiv einen domänenübergreifenden POST-Aufruf, einschließlich angehängter Dateien und mehrteiliger Dateien 🙂

Hier sind zuerst die Schritte in Verstehen die Idee, danach – finden Sie ein Implementierungsbeispiel.

Wie ist JSONP von jQuery implementiert und warum unterstützt es keine POST-Anfragen?

Während das traditionelle JSONP implementiert wird, indem ein Skriptelement erstellt und an das DOM angehängt wird – was dazu führt, dass der Browser eine HTTP-Anfrage auslöst, um die Quelle für das Tag abzurufen, und sie dann als JavaScript ausführt, wird die HTTP-Anfrage, die der Browser auslöst ist einfach GET.

Was ist nicht auf GET-Anfragen beschränkt?

EINE FORM. Senden Sie das FORMULAR während der Angabe action der Cross-Domain-Server. Ein FORM-Tag kann vollständig mit einem Skript erstellt, mit allen Feldern mit einem Skript gefüllt, alle notwendigen Attribute gesetzt, in das DOM eingefügt und dann gesendet werden – alles mit einem Skript.

Aber wie können wir ein FORMULAR einreichen, ohne die Seite zu aktualisieren?

Wir spezifizieren die target das Formular zu einem IFRAME auf derselben Seite. Ein IFRAME kann auch mithilfe eines Skripts erstellt, festgelegt, benannt und in das DOM eingefügt werden.

Aber wie können wir diese Arbeit vor dem Benutzer verbergen?
Wir enthalten sowohl FORM als auch IFRAME in einem versteckten DIV mit style="display:none"

(Und hier ist der komplizierteste Teil der Technik, seien Sie geduldig)

Aber IFRAME von einer anderen Domäne kann keinen Rückruf für das Dokument der obersten Ebene aufrufen. Wie kann man das überwinden?

Wenn eine Antwort von FORM Submit eine Seite aus einer anderen Domäne ist, führt jede Skriptkommunikation zwischen der Seite der obersten Ebene und der Seite im IFRAME zu “Zugriff verweigert”. Der Server kann also nicht mit einem Skript zurückrufen. Was kann der Server tun? umleiten. Der Server kann auf jede beliebige Seite umleiten – einschließlich Seiten in derselben Domäne wie das Dokument der obersten Ebene – Seiten, die den Rückruf für uns aufrufen können.

Wie kann ein Server umleiten?

zwei Wege:

  1. Verwenden von clientseitigen Skripten wie <Script>location.href="https://stackoverflow.com/questions/5345493/some-url"</script>
  2. HTTP-Header verwenden. Sehen: http://www.webconfs.com/how-to-redirect-a-webpage.php

Also habe ich am Ende eine andere Seite? Wie hilft es mir?

Dies ist eine einfache Dienstprogrammseite, die von allen domänenübergreifenden Aufrufen verwendet wird. Eigentlich ist diese Seite eine Art Proxi, aber es ist kein Server, sondern ein einfache und statische HTML-Seite, die jeder mit Notepad und Browser verwenden kann.

Alles, was diese Seite tun muss, ist den Callback auf dem Dokument der obersten Ebene mit den Antwortdaten vom Server aufzurufen. Clientseitiges Scripting hat Zugriff auf alle URL-Teile, und der Server kann seine Antwort als Teil davon codiert dort ablegen, sowie den Namen des aufzurufenden Callbacks. Bedeutet – diese Seite kann eine statische und eine HTML-Seite sein und muss keine dynamische serverseitige Seite sein 🙂

Diese Dienstprogrammseite nimmt die Informationen von der URL, in der sie ausgeführt wird – insbesondere in meiner Implementierung unten – die Query-String-Parameter (oder Sie können Ihre eigene Implementierung mit der Anker-ID schreiben – dh dem Teil einer URL rechts neben dem “#” Unterschrift). Und da diese Seite statisch ist, darf sie sogar zwischengespeichert werden 🙂

Wird nicht für jede POST-Anfrage ein DIV, ein SCRIPT und ein IFRAME hinzugefügt, irgendwann Speicherverlust?

Wenn Sie es auf der Seite belassen – wird es. Wenn Sie nach Ihnen putzen – wird es nicht. Alles, was wir tun müssen, ist, dem DIV eine ID zu geben, die wir verwenden können, um das DIV und das darin enthaltene FORM und IFRAME zu löschen, wenn die Antwort vom Server ankommt oder das Zeitlimit überschritten wird.

Was bekommen wir?

Effektiv ein domänenübergreifender POST-Aufruf, einschließlich angehängter Dateien und mehrteilig und alles 🙂

Was sind die Grenzen?

  • Die Serverantwort ist auf alles beschränkt, was in eine Umleitung passt.
  • Der Server muss IMMER eine REDIRECT-Anforderung an eine POST-Anforderung zurückgeben. Dazu gehören 404- und 500-Fehler. Alternativ können Sie auf dem Client eine Zeitüberschreitung erstellen, kurz bevor Sie die Anfrage auslösen, damit Sie die Möglichkeit haben, Anfragen zu erkennen, die nicht zurückgegeben wurden.
  • nicht jeder kann all dies und alle damit verbundenen Phasen verstehen. Es ist eine Art Arbeit auf Infrastrukturebene, aber wenn Sie es einmal zum Laufen gebracht haben, rockt es 🙂

Kann ich es für PUT- und DELETE-Aufrufe verwenden?

FORM-Tag führt weder PUT noch DELETE aus. Aber das ist besser als nichts 🙂

Okay, hab das Konzept verstanden. Wie wird das technisch gemacht?

Was ich mache ist:

Ich erstelle das DIV, formatiere es als unsichtbar und hänge es an das DOM an. Ich gebe ihm auch eine ID, mit der ich es aus dem DOM bereinigen kann, nachdem die Serverantwort angekommen ist (genauso wie JQuery seine JSONP SCRIPT-Tags bereinigt – aber das DIV).

Dann bin ich komponieren einen String, der sowohl IFRAME als auch FORM enthält – mit allen Attributen, Eigenschaften und Eingabefeldern – und in das unsichtbare DIV einschleusen. Es ist wichtig, diesen String erst in das DIV zu injizieren, NACHDEM sich das Div im DOM befindet. Wenn nicht, funktioniert es nicht in allen Browsern.

Danach erhalte ich einen Hinweis auf das FORMULAR und schicke es ab. Denken Sie nur an eine Zeile davor – um a . zu setzen Timeout-Rückruf falls der Server nicht oder falsch antwortet.

Die Callback-Funktion enthält den Bereinigungscode. Es wird auch im Falle eines Antwort-Timeouts vom Timer aufgerufen (und bereinigt seinen Timeout-Timer, wenn eine Serverantwort eintrifft).

Zeig mir den Code!

Der Code-Schnipsel unten ist bei “reinem” Javascript völlig “neutral” und deklariert jedes benötigte Dienstprogramm. Nur zur Vereinfachung der Erklärung der Idee – alles läuft auf globaler Ebene, sollte jedoch etwas anspruchsvoller sein …

Organisieren Sie es nach Belieben in Funktionen und parametrieren Sie, was Sie brauchen – aber stellen Sie sicher, dass alle Teile, die sich gegenseitig sehen müssen, im gleichen Umfang laufen 🙂

Nehmen Sie für dieses Beispiel an, der Client läuft weiter http://samedomain.com und der Server läuft weiter http://crossdomain.com.

Der Skriptcode im Dokument der obersten Ebene

//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();

Der Server auf der Cross-Domain
Als Antwort vom Server wird eine REDIRECTION erwartet, entweder per HTTP-Header oder durch Schreiben eines SCRIPT-Tags. (Umleitung ist besser, SCRIPT-Tag ist mit JS-Haltepunkten einfacher zu debuggen). Hier ist das Beispiel für den Header unter der Annahme, dass rurl Wert von oben

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

Beachten Sie, dass

  • der Wert der data Argument kann ein JavaScript Object-Literal- oder JSON-Ausdruck sein, es sollte jedoch besser URL-codiert sein.
  • Die Länge der Serverantwort ist auf die Länge einer URL beschränkt, die ein Browser verarbeiten kann.

Außerdem – in meinem System hat der Server einen Standardwert für die rurl so dass dieser Parameter optional ist. Dies ist jedoch nur möglich, wenn Ihre Client-Anwendung und Ihre Server-Anwendung gekoppelt sind.

APIs zum Ausgeben des Umleitungsheaders:

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

Alternativ können Sie den Server Folgendes als Antwort schreiben lassen:

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

Aber HTTP-Header wären sauberer 😉

Die Dienstprogrammseite in derselben Domäne wie das Dokument der obersten Ebene

Ich verwende die gleiche Utility-Seite wie rurl Für alle meine Post-Anfragen: Alles, was es tut, ist, den Namen des Callbacks und die Parameter aus dem Query-String mit clientseitigem Code zu nehmen und es im übergeordneten Dokument aufzurufen. Es kann es tun NUR wenn diese Seite in GENAU der gleichen Domain läuft wie die Seite, die die Anfrage ausgelöst hat! Wichtig: Im Gegensatz zu Cookies – Subdomains zählen nicht!! Es muss die exakt gleiche Domäne sein.

Es macht es auch effizienter, wenn diese Dienstprogrammseite keine Verweise auf andere Ressourcen enthält – einschließlich JS-Bibliotheken. Diese Seite ist also reines JavaScript. Aber Sie können es nach Belieben implementieren.

Hier ist die Responder-Seite, die ich verwende, deren URL in der gefunden wird rurl der POST-Anfrage (im Beispiel: 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: nn" + e.message;
}
</script>
</head><body></body></html>

Es ist nicht viel Automatisierung und ‘fertige’ Bibliothek wie jQuery und beinhaltet etwas ‘manuelle’ Arbeit – aber es hat den Charme 🙂

Wenn Sie ein begeisterter Fan von vorgefertigten Bibliotheken sind, können Sie auch nachsehen Dojo-Toolkit dass, als ich das letzte Mal überprüft habe (vor etwa einem Jahr) – eine eigene Implementierung für den gleichen Mechanismus hatte.
http://dojotoolkit.org/

Viel Glück Kumpel, ich hoffe es hilft…

  • „4. POST die Seite an den Server“ – welcher Server? Ich verstehe deine Beschreibung dieser Methode nicht wirklich.

    – Paul D. Waite

    17. März ’11 um 22:55


  • Wie ich versprochen habe, habe ich Codebeispiele hinzugefügt. Ich musste alle Teile aus dem Projekt entfernen, die “geheime Soße” des Projekts sind, an dem ich arbeite, und die einfachste Möglichkeit bieten, die Idee zu erklären. Lass es mich wissen, wenn du immer noch siehst, dass die Dinge weiterer Klärung bedürfen 🙂

    – Radagast der Braune

    19. März ’11 um 8:33


  • Welche vorhandenen APIs können Sie nennen, die Schritt 4 unterstützen? “Nach der Verarbeitung der Anfrage gibt der Server … eine Weiterleitung an die rurl Parameter”

    – Crescent Fresh

    20. März ’11 um 4:04

  • @Radagast: nein, was? JSONP-API sind für Schritt 4 ausgelegt?

    – Crescent Fresh

    21. März ’11 um 22:26

  • Das ist wirklich ein spektakulärer Einsatz von Fantasie und technischem Know-how. Bravo!

    – Oligofren

    7. Juli ’11 um 16:34

Gibt es eine Möglichkeit, eine JSONP-Anfrage mit POST/PUT/DELETE durchzuführen?

Nein gibt es nicht.

  • @Darin Dimitrov, vielleicht suchte er nach einem Vorschlag, was er zusätzlich zur Antwort versuchen sollte.

    – Der Muffin-Mann

    17. März ’11 um 21:46

  • @Nick, er fragt nach jQuery und erklärt, dass er auch eine Javascript-Lösung nehmen würde und nach Codebeispielen für eine funktionierende Lösung sucht. Ich denke, meine Antwort ist in diesem Fall angepasst.

    – Darin Dimitrov

    17. März ’11 um 21:48

  • Dann lass mich dich überraschen. Siehe unten 🙂

    – Radagast der Braune

    17. März ’11 um 21:50

  • @Radagast the Brown, er fragt auch nach DELETE und PUT. Ich kann in Ihrer Antwort nichts über diese Verben sehen, während meine sie behandeln 🙂 +1 übrigens zu Ihrer Antwort. Das ist ein guter.

    – Darin Dimitrov

    17. März ’11 um 21:50


Nein. Überlegen Sie, was JSONP ist: eine Injektion eines neuen <script> Tag im Dokument. Der Browser führt a GET Aufforderung zum Abrufen des Skripts, auf das die zeigt src Attribut. Es gibt keine Möglichkeit, dabei ein anderes HTTP-Verb anzugeben.

  • Anstatt uns mit der JSONP-Methode, die die POST-Methode standardmäßig nicht unterstützt, den Kopf zu hämmern, können wir loslegen CORS .Das bringt keine großen Änderungen an der herkömmlichen Art der Programmierung. Durch einen einfachen Jquery-Ajax-Aufruf können wir mit Cross-Domains umgehen.
  • Bei der CORS-Methode müssen Sie Header in der serverseitigen Skriptdatei oder im Server selbst (in der Remotedomäne) hinzufügen, um diesen Zugriff zu ermöglichen. Dies ist sehr zuverlässig, da wir verhindern oder einschränken können, dass die Domänen unerwünschte Anrufe tätigen.
  • Es ist im Detail zu finden in Wikipedia Seite.

.

306280cookie-checkVerwenden von PUT/POST/DELETE mit JSONP und jQuery

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy