クロスドメインリクエスト、JSON/JSONPサポート、およびメインHTTPメソッド(PUT/GET/POST/DELETE)をサポートするRESTful APIの作成に取り組んでいます。サーバー側のコードを介してこのAPIに簡単にアクセスできるようになりましたが、javascriptに公開するのは良いことです。私が知ることができることから、jQueryでJSONPリクエストを行うとき、それはGETメソッドのみをサポートします。 POST/PUT/DELETEを使用してJSONPリクエストを行う方法はありますか?
理想的には、jQuery内から(コアがこれをサポートしていない場合はプラグインを使用して)これを実行する方法が必要ですが、プレーンなJavaScriptソリューションも使用します。動作中のコードへのリンク、またはコーディング方法は参考になります。ありがとうございます。
実際には、POST要求をサポートする方法があります。PROXIサーバーには必要ありません。以下に説明する小さなユーティリティHTMLページだけです。
最初にunderstandアイデアのステップを示します。その後、実装サンプルを見つけます。
jQueryのJSONPの実装方法と、なぜPOSTリクエスト?をサポートしないのか
従来のJSONPは、スクリプト要素を作成してDOMに追加することで実装されますが、ブラウザがHTTPリクエストを実行してタグのソースを取得し、JavaScriptとして実行するように強制する結果、ブラウザが起動するHTTPリクエスト単純なGETです。
GETリクエストに限定されないものは何ですか?
フォーム。 action
クロスドメインサーバーを指定しながら、フォームを送信します。 FORMタグは、スクリプトを使用して完全に作成し、スクリプトを使用してすべてのフィールドを入力し、必要なすべての属性を設定し、DOMに挿入して送信します。すべてスクリプトを使用します。
しかし、ページを更新せずにフォームを送信するにはどうすればよいですか?
同じページのIFRAMEにtarget
フォームを指定します。スクリプトを使用して、IFRAMEを作成、設定、名前付け、DOMに挿入することもできます。
しかし、この作業をユーザーから隠すにはどうすればよいですか?style="display:none"
を使用して、非表示のDIVにFORMとIFRAMEの両方を含めます
(そして、ここがテクニックの最も複雑な部分です、我慢してください)
しかし、別のドメインからのIFRAMEは、そのトップレベルドキュメントでコールバックを呼び出すことができません。それを克服する方法は?
実際、FORMサブミットからの応答が別のドメインからのページである場合、トップレベルページとIFRAME内のページ間のスクリプト通信は「アクセス拒否」になります。そのため、サーバーはスクリプトを使用してコールバックできません。サーバーは何ができますか? リダイレクト。サーバーは、トップレベルドキュメントと同じドメイン内のページを含む任意のページにリダイレクトできます。このページは、コールバックを呼び出すことができます。
サーバーはどのようにリダイレクトできますか?
二通り:
<Script>location.href = 'some-url'</script>
などのクライアント側スクリプトを使用するだから私は別のページになりますか?どのように役立ちますか?
これは、すべてのクロスドメインコールから使用されるシンプルなユーティリティページです。実際、このページは実際には一種のプロキシですが、サーバーではなく、メモ帳とブラウザを使用する誰でも使用できるシンプルで静的なHTMLページです。
このページで行う必要があるのは、サーバーからの応答データを使用して、トップレベルドキュメントでコールバックを呼び出すことだけです。クライアント側のスクリプトはすべてのURL部分にアクセスでき、サーバーはその一部としてエンコードされた応答と、呼び出す必要のあるコールバックの名前をそこに置くことができます。意味-このページは静的なHTMLページにすることができ、動的なサーバー側ページである必要はありません:)
このユーティリティページは、実行するURLから(具体的には以下の実装で)Query-Stringパラメーターから情報を取得します(または、アンカーIDを使用して独自の実装を記述できます。つまり、URLの「#」符号)。また、このページは静的であるため、キャッシュすることも許可されます:)
POST DIV、SCRIPT、IFRAMEを要求すると、最終的にメモリリークが発生しますか?
あなたがページに残した場合-それはします。あなたの後に掃除する場合-それはしません。行う必要があるのは、サーバーから応答が到着するかタイムアウトになるたびに、DIVとその中のFORMおよびIFRAMEを整理するために使用できるIDをDIVに与えることです。
何が得られますか?
制限は何ですか?
PUTおよびDELETE呼び出しに使用できますか?
FORMタグはPUTおよびDELETEしません。しかし、それは何よりも良いです:)
OK、コンセプトを得た。技術的にはどうですか?
私がやることは:
DIVを作成し、非表示としてスタイルを設定し、DOMに追加します。また、サーバーの応答が到着した後にDOMからクリーンアップできるIDを提供します(JQueryがJSONP SCRIPT tasgs-DIVをクリーンアップするのと同じ方法)。
次に、I compose IFRAMEとFORMの両方を含む文字列-すべての属性、プロパティ、および入力フィールドを使用して、非表示のDIVに挿入します。 divがDOMに入った後にのみ、この文字列をDIVに挿入することが重要です。そうでない場合-すべてのブラウザで動作しません。
その後-フォームへの参照を取得して送信します。その前の1行を覚えておいてください-サーバーが応答しない場合、または間違った方法で応答する場合にTimeoutコールバックを設定します。
コールバック関数には、クリーンアップコードが含まれています。また、応答タイムアウトの場合にタイマーによって呼び出されます(サーバー応答が到着したときにタイムアウトタイマーを消去します)。
コードを見せてください!
以下のコードスニペットは、「純粋な」JavaScriptで完全に「中立」であり、必要なユーティリティを宣言します。アイデアの説明を簡単にするために-それはすべてグローバルスコープで実行されますが、もう少し洗練されたものでなければなりません...
必要に応じて関数でそれを整理し、必要なものをパラメータ化します-しかし、お互いを見る必要があるすべての部分が同じスコープで実行されるようにしてください:)
この例では、クライアントが http://samedomain.com で実行され、サーバーが http://crossdomain.com で実行されると仮定します。
最上位ドキュメントのスクリプトコード
//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,""");//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();
クロスドメイン上のサーバーサーバーからの応答は、HTTP-HeaderまたはSCRIPTタグの作成によるリダイレクトであると予想されます。 (リダイレクトが優れている、SCRIPTタグはJSブレークポイントを使用してデバッグする方が簡単です)。上記のrurl
値を想定したヘッダーの例は次のとおりです。
Location: http://samedomain.com/HTML/page?callback=myAsyncJSONPCallback&data=whatever_the_server_has_to_return
ご了承ください
data
引数の値はJavaScript Object-LiteralまたはJSON式にすることができますが、URLエンコードする方が適切です。また、私のシステムでは、サーバーにはrurl
のデフォルト値があるため、このパラメーターはオプションです。ただし、これは、クライアントアプリケーションとサーバーアプリケーションが結合されている場合にのみ可能です。
リダイレクトヘッダーを発行するAPI:
http://www.webconfs.com/how-to-redirect-a-webpage.php
または、サーバーに応答として次のように書き込ませることもできます。
<script>
location.href="http://samedomain.com/HTML/page?callback=myAsyncJSONPCallback&data=whatever_the_server_has_to_return"
</script>
ただし、HTTPヘッダーはよりクリーンであると見なされます;)
トップレベルドキュメントと同じドメインのユーティリティページ
すべての投稿要求にrurl
と同じユーティリティページを使用します。クライアント側コードを使用してQuery-Stringからコールバックの名前とパラメーターを取得し、親ドキュメントで呼び出します。このページがリクエストを実行したページと同じドメインで実行されている場合にのみ、それを行うことができます[〜#〜] only [〜#〜]! 重要:Cookieとは異なり、サブドメインはカウントされません!!彼にはまったく同じドメインが必要です。
また、このユーティリティページに、JSライブラリを含む他のリソースへの参照が含まれていない場合は、より効率的になります。したがって、このページは単純なJavaScriptです。ただし、好きなように実装できます。
私が使用するレスポンダーページは次のとおりです。URLはPOSTリクエストのrurl
にあります(例では 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>
それはあまり自動化されておらず、jQueryのような「既製の」ライブラリーであり、「手動」の作業を伴いますが、魅力があります:)
既製のライブラリの熱心なファンなら-Dojo Toolkitもチェックできます。最後にチェックしたとき(約1年前)-同じメカニズムの独自の実装がありました。 http://dojotoolkit.org/
幸運の相棒、私はそれが役立つことを願っています...
POST/PUT/DELETEを使用してJSONPリクエストを行う方法はありますか?
ありません。
いいえ。JSONPとは何かを検討してください。新しい<script>
タグがドキュメントにあります。ブラウザはGET
リクエストを実行して、src
属性が指すスクリプトをプルします。これを行うときに他のHTTP動詞を指定する方法はありません。