動的にiframeを生成してクロスドメインなPOSTを投げる方法

※2015/3/15追記

2015/2月ごろから本記事の方法はTwitterでの実利用は困難になりました。レスポンスヘッダに"content-disposition: attachment; filename=json.json"が追加されるようになったため、json.jsonというファイルとしてダウンロードが行われてしまいます。現状でこれを回避する方法はないと思われ、POSTはサーバ経由で行うしかなさそうです。(JSONPを利用したGETはこのヘッダがあっても可能です。)
=====追記以上====



twicli開発メモ - Okiraku Programming で、iframeをtargetに指定してformを送信することで、外部ドメインに対してPOSTメソッドを発行する方法を書きました。が、iframeをあらかじめ準備する必要があったため、複数のクエリを同時発行できないといった欠点がありました。


例えば、twicliでは☆をクリックすることで発言をfavる(お気に入りに追加する)ことができますが、複数の発言をfavろうとして☆を連打するとformが途中でキャンセルされてfavできないことがありました。


そこで以下のスクリプトでは、formとiframeを動的に生成することで、連続してクエリを投げられるようにしました。


またonloadを使ってPOST完了を検知できますので、そこで何らかのスクリプトを実行したりすることもできます。また、そのタイミングで不要になったiframeは自動で削除されます。
ただし相変わらず結果は取れませんが。。。


動作はSafari, Firefox, Opera, おまけにIEも対応です。スクリプトは以下。

<input type="button" onClick="postInIFrame('http:/example.com/')" value="POST">

<script>
var seq = 0;                                   // フレーム識別用のID
function postInIFrame(url) {
  var frm = document.createElement("form");    // POST用のフォームを生成
  frm.action = url;
  frm.method = "POST";
  frm.target = "pfr" + seq;
  document.body.appendChild(frm);
  var pfr = document.createElement("iframe"); // formのtargetとなるiframeを生成
  pfr.name = "pfr" + (seq++);
  pfr.src = "about:blank";                    // 直後はabout:blankを表示する
  var cnt = 0;                                // 下のクロージャ内で使うカウンタ
  var onload = pfr.onload = function(){
    if (cnt++ == 0)
      setTimeout(function(){ frm.submit(); }, 0); // iframeが準備できたらフォームを送信
    else {
      frm.parentNode.removeChild(frm);        // フォーム受信後、form,iframeを削除
      pfr.parentNode.removeChild(pfr);
    }
  };
  if (document.all) pfr.onreadystatechange = function(){ /* for IE */
    if (this.readyState == "complete") {     // onloadが動作しないので代用
      pfr.contentWindow.name = pfr.name;     // こちらに名前をsetしないとtargetが動作しない
      onload();
    }
  };
  document.body.appendChild(pfr);
}
</script>