38 votes

Utilisation de PUT / POST / DELETE avec JSONP et jQuery

Je suis en train de travailler sur la création d'une API RESTful qui prend en charge les demandes inter-domaine, JSON/JSONP de soutien, et la principale méthode HTTP (PUT/GET/POST/DELETE). Maintenant, tout sera facile d'accéder à cette API via le serveur de code côté , il serait agréable de exposée à javascript. À partir de ce que je peux dire, lors d'une JSONP demandes avec jQuery, il ne supporte que la méthode GET. Est-il un moyen de faire un JSONP demande l'aide de POST/PUT/DELETE?

Idéalement, je voudrais un moyen de le faire à partir de jQuery (par le biais d'un plugin si le noyau ne supporte pas ça), mais je vais prendre un simple javascript solution. Tous les liens de travail ou de code comment code, il serait utile, merci.

70voto

Radagast the Brown Points 1427

En fait - il un moyen de soutenir les requêtes POST. Et il n'est pas nécessaire dans un serveur PROXI - juste un petit utilitaire page HTML qui est décrit ci-dessous.

Voici comment obtenir Efficacement un POSTE de la croix-domaine d'appel, y compris les fichiers joints et multi-partie et le tout :)

Voici les premières sont les étapes de la compréhension de l'idée, après - trouver une mise en œuvre de l'échantillon.

Comment JSONP de jQuery est mis en œuvre, et pourquoi ne pas l'appui des requêtes POST?

Alors que le traditionnel JSONP est mis en œuvre par la création d'un élément de script et en les ajoutant dans les DOM - ce que les résultats inforcing le navigateur de l'incendie d'une requête HTTP pour récupérer la source de la balise, puis de l'exécuter JavaScript, la requête HTTP au navigateur d'incendies est simple à OBTENIR.

Ce n'est pas limité à des demandes?

UN FORMULAIRE. Soumettre le FORMULAIRE tout en spécifiant action la croix-serveur de domaine. Une balise de FORMULAIRE peuvent être créés entièrement à l'aide d'un script, peuplé de tous les champs à l'aide de script, de définir tous les attributs nécessaires, injecté dans les DOM, puis soumis à l' - le tout à l'aide d'un script.

Mais comment peut-on soumettre un FORMULAIRE sans rafraichissement de la page?

Nous spécifier l' target la forme d'une IFRAME dans la même page. Un IFRAME peut également être créé, ensemble, nommé et injecté dans les DOM à l'aide d'un script.

Mais Comment pouvons-nous cacher ce travail de l'utilisateur? Nous allons contiennent à la fois de la FORME et de l'IFRAME caché dans un DIV à l'aide de style="display:none"

(et c'est ici la partie la plus compliquée de la technique, être patient)

Mais IFRAME à partir d'un autre domaine ne peut pas appeler un rappel sur le document de niveau supérieur. Comment surmonter cela?

En effet , si une réponse de soumettre le FORMULAIRE, c'est une page à partir d'un autre domaine, n'importe quel script de communication entre le niveau supérieur de la page et de la page dans l'IFRAME résultats dans "accès refusé". Si le serveur ne peut pas de rappel à l'aide d'un script. Ce que le serveur peut faire? rediriger. Le serveur peut rediriger vers une page - y compris les pages dans le même domaine que le document de niveau supérieur de pages qui peut appeler la fonction de rappel pour nous.

Comment un serveur de redirection?

de deux façons:

  1. À l'aide de script côté client, comme <Script>location.href = 'some-url'</script>
  2. À l'aide de HTTP en-Tête. Voir: http://www.webconfs.com/how-to-redirect-a-webpage.php

Donc je me retrouve avec une autre page? Comment fait-il m'aider?

C'est un utilitaire simple page qui sera utilisé à partir de tous les inter-domaine d'appels. En fait, cette page est en fait une sorte de proxi, mais il n'est pas un serveur, mais un simple et statique de la page HTML, que n'importe qui avec le bloc-notes et un navigateur peut utiliser.

Tous cette page a à faire est d'appeler la fonction de rappel sur le document de niveau supérieur, avec la réponse de données à partir du serveur. Les scripts Côté Client a accès à toutes les URL des pièces, et le serveur peut mettre sa réponse codée dans le cadre de ce dernier, ainsi que le nom de la fonction de rappel qui doit être invoquée. Signifie - cette page peut être une statique et une page HTML, et n'a pas à être une dynamique côté serveur de la page :)

Cet utilitaire page les informations à partir de l'URL il s'exécute en particulier dans mon de la mise en œuvre soufflet - la Chaîne de la Requête de paramètres (ou vous pouvez écrire votre propre mise en œuvre à l'aide de l'ancre-ID - je.e la partie de l'url à droite pour le signe"#"). Et depuis cette page est statique - il peut même être autorisés à être mis en cache :)

Ne pas ajouter pour chaque requête POST un DIV, un SCRIPT et une IFRAME, éventuellement, une fuite de mémoire?

Si vous la laissez dans la page - il. Si vous nettoyer après vous, il ne sera pas. Tout ce que nous avons à faire est de donner une ID de la DIV que nous pouvons utiliser pour celan-up de la DIV et de la FORME et de l'IFRAME à l'intérieur chaque fois que la réponse arrive sur le serveur, ou heures.

Qu'obtenons-nous?

Efficacement un POSTE de la croix-domaine d'appel, y compris les fichiers joints et multi-partie et le tout :)

Quelles sont les limites?

  • La réponse du serveur est limité à ce qui s'inscrit dans une redirection.
  • Le serveur doit TOUJOURS retourner une REDIRECTION vers un POSTE de demandes. Qui comprennent 404 et 500 erreurs. Alternativement créer un timeout sur le client juste avant le déclenchement de la demande, de sorte que vous aurez une chance de détecter les demandes qui n'ont pas retourné.
  • pas tout le monde peut comprendre tout cela et toutes les étapes. c'est une sorte d'une infrastructure de travail, mais une fois que vous l'obtenir en cours d'exécution - ça déchire :)

Puis-je l'utiliser pour METTRE et SUPPRIMER des appels?

Balise de FORMULAIRE ne PUT et DELETE. Mais c'est mieux que rien :)

Ok, a obtenu le concept. Comment faire techniquement?

Ce que je fais, c'est:

Je crée un DIV, style comme invisibles, et l'ajouter à la DOM. J'ai également donner une ID je peux nettoyer ça dans les DOM après la réponse du serveur est arrivé (de la même façon JQuery nettoie c'est JSONP SCRIPT tasgs - mais la DIV).

Puis-je composer une chaîne qui contient l'IFRAME et la FORME - avec tous les attributs, les propriétés et les champs de saisie, et de l'injecter dans l'invisible DIV. il est important d'injecter de cette chaîne dans le DIV seulement APRÈS le div est dans les DOM. Sinon il ne fonctionnera pas sur tous les navigateurs.

Après que - je obtenir une référence de la FORME et de la soumettre. Rappelez-vous juste une ligne avant que - pour définir un Délai d'attente de rappel au cas où le serveur ne répond pas ou répond de manière incorrecte.

La fonction de rappel contient le code de nettoyage. Il est aussi appelé par minuterie dans le cas d'une réponse-délai d'attente (et la nettoie de délai du retardateur lorsqu'une réponse du serveur arrive).

Montrez-moi le code!

L'extrait de code soufflet est totalement "neutre" sur "pure" de javascript, et déclare quelle que soit l'utilitaire dont il a besoin. Juste pour la simplification d'expliquer l'idée - qu'il s'exécute tout sur la portée globale, cependant, il devrait être un peu plus sophistiquée...

Organiser dans les fonctions que vous pouvez et de paramétrer ce que vous avez besoin - mais assurez-vous que toutes les pièces qui ont besoin de voir les uns les autres s'exécutent sur le même champ d'application :)

Pour cet exemple, supposons que le client s'exécute sur l' http://samedomain.com et le serveur s'exécute sur l' http://crossdomain.com.

Le code de script sur le document de niveau supérieur

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

Le serveur sur le cross-domain La réponse du serveur est prévu pour être une REDIRECTION, soit par HTTP en-Tête ou par écrit une balise SCRIPT. (redirection est mieux, balise de SCRIPT est plus facile à déboguer avec JS points d'arrêt). Voici l'exemple de l'en-tête, en supposant que l' rurl de la valeur à partir de ci-dessus

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

Notez que

  • la valeur de l' data argument peut être un Objet JavaScript Littéral ou JSON expression, cependant, il vaut mieux être url-encodé.
  • la longueur de la réponse du serveur est limitée à la longueur d'une URL d'un navigateur capable de traiter.

Aussi, dans mon système, le serveur a une valeur par défaut pour l' rurl , de sorte que ce paramètre est facultatif. Mais vous pouvez le faire uniquement si votre application cliente et le serveur d'application sont couplés.

Api pour émettre de la redirection d'en-tête:

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

Alternativement, vous pouvez demander au serveur d'écrire comme une réponse suivants:

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

Mais HTTP-en-Têtes de serait considérée comme plus propre ;)

La page d'utilité sur le même domaine que le document de niveau supérieur

J'utilise la même page d'utilité en tant que rurl pour toutes mes demandes post: il n'est de prendre le nom de la fonction de rappel et les paramètres de la Chaîne de la Requête à l'aide de code côté client, et de l'appeler sur le document parent. Il peut le faire SEULEMENT lorsque cette page s'exécute dans le même domaine que la page qui a déclenché la demande! Important: à la différence des cookies - les sous-domaines ne comptent pas!! Il a à la il a exactement le même domaine.

C'est aussi de la rendre plus efficace si cet utilitaire page ne contient pas de références à d'autres ressources -y compris les bibliothèques JS. Alors cette page est la plaine de JavaScript. Mais vous pouvez la mettre en œuvre comme il vous plaît.

Voici le répondeur page que j'utilise, qui est l'URL se trouve dans l' rurl de la requête POST (dans l'exemple: 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>

Il n'est pas beaucoup d'automatisation et de "ready-made" de la bibliothèque comme jQuery et involes certains "manuelle" de travail, mais il a du charme :)

Si vous êtes un fan de prêt-à-bibliothèques - vous pouvez aussi consulter Dojo Toolkit que lors de la dernière, j'ai vérifié (environ un an), - avaient leur propre mise en œuvre, pour le même mécanisme. http://dojotoolkit.org/

Bonne chance l'ami, j'espère que ça aide...

13voto

Darin Dimitrov Points 528142

Est-il possible de faire une demande JSONP en utilisant POST / PUT / DELETE?

Non il n'y en a pas.

8voto

lwburk Points 29313

Considérez ce que JSONP est: une injection d'une nouvelle balise <script> dans le document. Le navigateur effectue une demande GET pour extraire le script désigné par l'attribut src . Il est impossible de spécifier un autre verbe HTTP en procédant de la sorte.

2voto

Ganesh Points 609
  • Plutôt que de taper la tête avec JSONP méthode, qui en fait ne soutien POST-méthode par défaut, nous pouvons aller pour la SCRO .Qui fournira pas de grands changements dans la façon traditionnelle de la programmation. Par Jquery simple appel Ajax on peut aller avec la croix domaines.
  • Dans la SCRO méthode, vous devez ajouter des en-têtes dans des scripts côté serveur de fichier, ou dans le serveur lui-même(dans le domaine distant), pour permettre cet accès. C'est bien sûr, car nous pouvons prévenir/limiter les domaines de la prise des appels indésirables.
  • Il peut être trouvé en détail dans le wikipedia de page.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X