web-dev-qa-db-ja.com

クロスドメインを送信する POST JavaScriptを介してリクエスト?

クロスドメインのPOSTリクエストをJavaScriptで送信する方法

注 - ページを更新してはいけません。後で応答を取得して解析する必要があります。

537
Ido Schacham

Update:続行する前に、CORSの html5rocksチュートリアル を読んで理解する必要があります。わかりやすく、非常に明確です。

POSTされるサーバーを制御する場合は、サーバーに応答ヘッダーを設定することにより、「クロスオリジンリソース共有標準」を利用します。この回答は、このスレッドの他の回答で説明されていますが、私の意見ではあまり明確ではありません。

要するに、from.com/1.htmlからto.com/postHere.phpへのクロスドメインPOSTの実現方法です(例としてPHPを使用)。注:Access-Control-Allow-OriginをNON OPTIONSリクエストに設定するだけです-この例では、常に小さなコードスニペットのすべてのヘッダーを設定します。

  1. PostHere.phpで次を設定します。

    switch ($_SERVER['HTTP_Origin']) {
        case 'http://from.com': case 'https://from.com':
        header('Access-Control-Allow-Origin: '.$_SERVER['HTTP_Origin']);
        header('Access-Control-Allow-Methods: GET, PUT, POST, DELETE, OPTIONS');
        header('Access-Control-Max-Age: 1000');
        header('Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With');
        break;
    }
    

    これにより、スクリプトでクロスドメインのPOST、GET、およびOPTIONSを作成できます。これを読み続けると明らかになります...

  2. JSからクロスドメインPOSTをセットアップします(jQueryの例):

    $.ajax({
        type: 'POST',
        url: 'https://to.com/postHere.php',
        crossDomain: true,
        data: '{"some":"json"}',
        dataType: 'json',
        success: function(responseData, textStatus, jqXHR) {
            var value = responseData.someKey;
        },
        error: function (responseData, textStatus, errorThrown) {
            alert('POST failed.');
        }
    });
    

ステップ2でPOSTを実行すると、ブラウザは「OPTIONS」メソッドをサーバーに送信します。これはブラウザが「スニフ」して、サーバーがPOSTを実行するのに適しているかどうかを確認します。サーバーは「Access-Control-Allow-Origin」で応答し、リクエストが「 http://from.com 」または「 https://from.com "。サーバーはそれで問題ないので、ブラウザーは2番目の要求(今回はPOST)を行います。クライアントが送信するコンテンツタイプを設定することをお勧めします。したがって、同様に許可する必要があります。

MDNには HTTPアクセス制御 についての優れた記事があり、フロー全体の仕組みの詳細を説明しています。彼らのドキュメントによると、「クロスサイトXMLHttpRequestをサポートするブラウザで動作する」はずです。ただし、ITHINKは最新のブラウザでのみクロスドメインPOSTが許可されるため、これは少し誤解を招く可能性があります。私はこれがsafari、chrome、FF 3.6でのみ動作することを確認しました。

これを行う場合は、次のことに注意してください。

  1. サーバーは、操作ごとに2つの要求を処理する必要があります
  2. セキュリティへの影響について考える必要があります。 「Access-Control-Allow-Origin:*」などの操作を行う前に注意してください
  3. これはモバイルブラウザでは機能しません。私の経験では、クロスドメインPOSTはまったく許可されていません。 Android、iPad、iPhoneをテストしました
  4. FF <3.6にはかなり大きなバグがあり、サーバーが400以外の応答コードを返し、応答本文(検証エラーなど)がある場合、FF 3.6は応答本文を取得しません。良いRESTプラクティスを使用できないので、これはロバにとって大きな痛みです。バグを参照してください ここ (jQueryでファイルされていますが、私の推測ではFFバグです-FF4で修正されているようです)。
  5. OPTIONリクエストだけでなく、常に上記のヘッダーを返します。 FFは、POSTからの応答でそれを必要とします。
378
rynop

リモートサーバーを制御する場合は、 この回答で説明されているように、おそらくCORSを使用する必要があります ; IE8以降、およびFF、GC、Safariのすべての最新バージョンでサポートされています。 (ただし、IE8および9では、CORSではリクエストでCookieを送信できません。)

したがって、リモートサーバーを制御しない場合、IE7をサポートする必要がある場合、またはCookieが必要でIE8 /をサポートする必要がある場合9、おそらくiframeテクニックを使用する必要があります。

  1. 一意の名前でiframeを作成します。 (iframeはブラウザー全体にグローバル名前空間を使用するため、他のWebサイトが使用しない名前を選択してください。)
  2. Iframeをターゲットにして、非表示の入力を持つフォームを構築します。
  3. フォームを送信します。

サンプルコードは次のとおりです。 IE6、IE7、IE8、IE9、FF4、GC11、S5でテストしました。

function crossDomainPost() {
  // Add the iframe with a unique name
  var iframe = document.createElement("iframe");
  var uniqueString = "CHANGE_THIS_TO_SOME_UNIQUE_STRING";
  document.body.appendChild(iframe);
  iframe.style.display = "none";
  iframe.contentWindow.name = uniqueString;

  // construct a form with hidden inputs, targeting the iframe
  var form = document.createElement("form");
  form.target = uniqueString;
  form.action = "http://INSERT_YOUR_URL_HERE";
  form.method = "POST";

  // repeat for each parameter
  var input = document.createElement("input");
  input.type = "hidden";
  input.name = "INSERT_YOUR_PARAMETER_NAME_HERE";
  input.value = "INSERT_YOUR_PARAMETER_VALUE_HERE";
  form.appendChild(input);

  document.body.appendChild(form);
  form.submit();
}

気をつけて! iframeは別のドメインに存在するため、POSTの応答を直接読み取ることはできません。フレームは異なるドメインから互いに通信することはできません。これは 同じ起源ポリシー です。

リモートサーバーを制御しているが、CORSを使用できない場合(たとえば、IE8/IE9を使用しているためCookieを使用する必要がある場合)、たとえば window.postMessage および/または古いブラウザでクロスドメインクロスフレームメッセージを送信できるようにするいくつかのライブラリの1つ:

リモートサーバーを制御しない場合、POST期間の応答を読み取ることができません。そうしないと、セキュリティ上の問題が発生します。

119
Dan Fabulich
  1. IFrameを作成します。
  2. 隠し入力を使ってフォームを作成します。
  3. フォームのアクションをURLに設定します。
  4. ドキュメントにiframeを追加
  5. フォームを送信する

疑似コード

 var ifr = document.createElement('iframe');
 var frm = document.createElement('form');
 frm.setAttribute("action", "yoururl");
 frm.setAttribute("method", "post");

 // create hidden inputs, add them
 // not shown, but similar (create, setAttribute, appendChild)

 ifr.appendChild(frm);
 document.body.appendChild(ifr);
 frm.submit();

あなたはおそらく、iframeをスタイルして、隠し絶対位置にしたいと思うでしょう。ブラウザによるクロスサイト投稿が許可されるかどうかはわかりませんが、許可されている場合はこれを実行する方法です。

46
Lou Franco

複雑にしないでおく:

  1. クロスドメインPOST:
    crossDomain: true,を使用

  2. ページを更新しないでください:
    いいえ、サーバーが応答を返すときにsuccessまたはerror asyncコールバックが呼び出されるため、ページは更新されません。


スクリプト例:

$.ajax({
        type: "POST",
        url: "http://www.yoururl.com/",
        crossDomain: true,
        data: 'param1=value1&param2=value2',
        success: function (data) {
            // do something with server response data
        },
        error: function (err) {
            // handle your error logic here
        }
    });
21
Alain Gauthier

関係するすべてのサーバーにアクセスできる場合は、他のドメインで要求されているページの返信のヘッダーに次のコードを追加してください。

PHP:

header('Access-Control-Allow-Origin: *');

たとえば、Drupalのxmlrpc.phpコードでは、これを行います。

function xmlrpc_server_output($xml) {
    $xml = '<?xml version="1.0"?>'."\n". $xml;
    header('Connection: close');
    header('Content-Length: '. strlen($xml));
    header('Access-Control-Allow-Origin: *');
    header('Content-Type: application/x-www-form-urlencoded');
    header('Date: '. date('r'));
    // $xml = str_replace("\n", " ", $xml); 

    echo $xml;
    exit;
}

これはおそらくセキュリティ上の問題を引き起こすので、リクエストを検証するために適切な措置を講じるようにしてください。

15
Robb Lovell
9
ndeuma
  1. 2つの隠しiframeを作成します(CSSスタイルに "display:none;"を追加します)。あなたの2番目のiframeがあなた自身のドメイン上の何かを指すようにしてください。

  2. 隠しフォームを作成し、そのメソッドをtarget =あなたの最初のiframeで "post"に設定し、必要に応じてenctypeを "multipart/form-data"に設定します(あなたが望むのでPOSTをしたいと思います)写真のようなマルチパートデータを送信するには?

  3. 準備ができたら、フォームにPOST()を送信させます。

  4. もしあなたが他のドメインがiframeとのクロスドメイン通信を行うjavascriptを返すことができるなら( http://softwareas.com/cross-domain-communication-with-iframes )そしてあなたは運がいいです、そしてあなたは応答もキャプチャできます。

もちろん、サーバーをプロキシとして使用したい場合は、これをすべて回避できます。自分のサーバーにフォームを送信するだけで、他のサーバーに要求が転送され(他のサーバーがIPの不一致に気付くように設定されていないと仮定して)、応答が得られます。

6
Magarshak

注意すべきもう一つの重要なこと! example の上に使い方の説明があります

$.ajax({
    type     : 'POST',
    dataType : 'json', 
    url      : 'another-remote-server',
    ...
});

JQuery 1.6以下には、クロスドメインXHRに関するバグがあります。 Firebugによると、OPTIONS以外のリクエストは送信されませんでした。 POSTなしまったく.

コードのテストと調整に5時間を費やしました。リモートサーバーに多くのヘッダーを追加する(スクリプト)。影響なし。しかし後になって、私はJQueryのlibを1.6.4に更新しました、そしてすべては魅力のように働きます。

6
BasTaller

JQuery AJAXを使用してASP.net MVC環境でこれを実行する場合は、次の手順に従います。(これは this threadで提供されるソリューションの概要です)

"caller.com"(任意のWebサイトにすることができます)が "server.com"(ASP.net MVCアプリケーション)に投稿する必要があるとします。

  1. "server.com"アプリのWeb.configに次のセクションを追加します。

      <httpProtocol>
          <customHeaders>
              <add name="Access-Control-Allow-Origin" value="*" />
              <add name="Access-Control-Allow-Headers" value="Content-Type" />
              <add name="Access-Control-Allow-Methods" value="POST, GET, OPTIONS" />
          </customHeaders>
      </httpProtocol>
    
  2. "server.com"で、投稿先のコントローラー( "Home"と呼ばれる)で次のアクションを実行します。

    [HttpPost]
    public JsonResult Save()
    {
        //Handle the post data...
    
        return Json(
            new
            {
                IsSuccess = true
            });
    }
    
  3. 次に、 "caller.com"から、次のようにフォーム(html ID "formId")からデータを "server.com"に投稿します。

    $.ajax({
            type: "POST",
            url: "http://www.server.com/home/save",
            dataType: 'json',
            crossDomain: true,
            data: $(formId).serialize(),
            success: function (jsonResult) {
               //do what ever with the reply
            },
            error: function (jqXHR, textStatus) {
                //handle error
            }
        });
    
5
Sujeewa

私は最善の方法はXMLHttpRequest(例えばjQueryでは$ .ajax()、$ .post())をCross-Origin Resource Sharing polyfillsの一つと一緒に使うことだと思います https://github.com/Modernizr/Modernizr/wiki/ HTML5-Cross-Browser-Polyfills#wiki-CORS

3
Roman Dolgiy

高レベル………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………).

あなたのページは動的に見えないiframeを作成し、それはother-server.comへのあなたのトランスポートとして機能します。あなたはそれからあなたのページからother-server.comにJSを通して通信しなければならなくて、あなたのページにデータを返すコールバックを持っています。

可能だがyour-server.comとother-server.comからの調整が必要

3
Dan

もう1つの方法があります(html5機能を使用)。他のドメインでホストされているプロキシiframeを使用することができます。そのiframeにpostMessageを使用してメッセージを送信すると、そのiframeはPOST request(同じドメイン上)を実行できます。

sender.comの親

var win = $('iframe')[0].contentWindow

function get(event) {
    if (event.Origin === "http://reciver.com") {
        // event.data is response from POST
    }
}

if (window.addEventListener){
    addEventListener("message", get, false)
} else {
    attachEvent("onmessage", get)
}
win.postMessage(JSON.stringify({url: "URL", data: {}}),"http://reciver.com");

reciver.comのiframe

function listener(event) {
    if (event.Origin === "http://sender.com") {
        var data = JSON.parse(event.data);
        $.post(data.url, data.data, function(reponse) {
            window.parent.postMessage(reponse, "*");
        });
    }
}
// don't know if we can use jQuery here
if (window.addEventListener){
    addEventListener("message", listener, false)
} else {
    attachEvent("onmessage", listener)
}
3
jcubic

これは古い質問ですが、いくつかの新しい技術が誰かを助けるかもしれません。

他のサーバーへの管理アクセス権がある場合は、オープンソースのForgeプロジェクトを使用してクロスドメインPOSTを実行できます。 Forgeは、FlashのrawソケットAPIを利用するクロスドメインのJavaScript XmlHttpRequestラッパーを提供しています。 POSTはTLSでも可能です。

POSTしようとしているサーバーへの管理アクセスが必要なのは、ドメインからのアクセスを許可するクロスドメインポリシーを提供する必要があるためです。

http://github.com/digitalbazaar/forge

2
dlongley

これは古い質問ですが、私は自分のアプローチを共有したいと思いました。私はプロキシとしてcURLを使いますが、とても簡単で一貫しています。 submit.phpというphpページを作成し、次のコードを追加します。

<?

function post($url, $data) {
$header = array("User-Agent: " . $_SERVER["HTTP_USER_AGENT"], "Content-Type: application/x-www-form-urlencoded");
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
$response = curl_exec($curl);
curl_close($curl);
return $response;
}

$url = "your cross domain request here";
$data = $_SERVER["QUERY_STRING"];
echo(post($url, $data));

次に、あなたのjs(ここではjQuery)に:

$.ajax({
type: 'POST',
url: 'submit.php',
crossDomain: true,
data: '{"some":"json"}',
dataType: 'json',
success: function(responseData, textStatus, jqXHR) {
    var value = responseData.someKey;
},
error: function (responseData, textStatus, errorThrown) {
    alert('POST failed.');
}
});
2
Ivan Durst

YQLカスタムテーブル+ JS XHRで可能になるはずです: http://developer.yahoo.com/yql/guide/index.html

私はそれを使用していくつかのクライアントサイド(js)htmlスクレイピングをします、うまくいきます(私は完全なオーディオプレーヤーを持っています、インターネット/プレイリスト/歌詞/最後のFM情報、すべてのクライアントjs + YQLで検索)

1
Guillaume86

クロスドメインサーバーにアクセスでき、サーバー側でコードを変更したくない場合は、 - xdomainというライブラリを使用できます。

使い方:

ステップ1:サーバ1:xdomainライブラリを含め、クロスドメインをスレーブとして設定します。

<script src="js/xdomain.min.js" slave="https://crossdomain_server/proxy.html"></script>

ステップ2:クロスドメインサーバーでproxy.htmlファイルを作成し、サーバー1をマスターとして含めます。

proxy.html:
<!DOCTYPE HTML>
<script src="js/xdomain.min.js"></script>
<script>
  xdomain.masters({
    "https://server1" : '*'
  });
</script>

ステップ3:

これで、server1からエンドポイントとしてproxy.htmlへのAJAX呼び出しを行うことができます。これはCORS要求をバイパスします。ライブラリは内部的にクレデンシャルとすべての可能なメソッドで動作するiframeソリューションを使用します:GET、POSTなど.

Ajaxコードを問い合わせます。

$.ajax({
        url: 'https://crossdomain_server/proxy.html',
        type: "POST",
        data: JSON.stringify(_data),
        dataType: "json",
        contentType: "application/json; charset=utf-8"
    })
    .done(_success)
    .fail(_failed)
1
Raj Malakpet

CORSはあなたのためです。 CORSは「クロスオリジンリソース共有」であり、クロスドメインリクエストを送信する方法です。NowXMLHttpRequest2とFetch APIの両方がCORSをサポートし、POSTとGETリクエストの両方を送信できます。

しかし、それには限界があります。サーバーは Access-Control-Allow-Origin を特別に要求する必要があり、 '*'に設定することはできません。

また、Originからリクエストを送信できるようにするには、JSONPが必要です( Access-Control-Allow-Origin も設定する必要がありますが、「*」にすることもできます)。

あなたが選択の仕方がわからない場合のリクエスト方法の多くのために、私はあなたがそれを行うために完全な機能的なコンポーネントが必要だと思います。私は簡単なコンポーネントを紹介しましょうcatta


最新のブラウザ(> IE9、Chrome、FF、Edgeなど)を使用している場合は、シンプルだが美しさのコンポーネントを使用することを強くお勧めしますhttps://github.com/Joker-Jelly/catta。依存関係はなく、3KB未満であり、同じ致命的なサンプル構文とオプションでFetch、AJAX、およびJSONPをサポートします。

catta('./data/simple.json').then(function (res) {
  console.log(res);
});

また、ES6モジュール、CommonJS、さらにはHTMLの<script>など、プロジェクトにインポートするためのすべての方法をサポートします。

1
Jelly