JavaScript経由でクロスドメインPOSTリクエストを送信するにはどうすればよいですか?


568

JavaScript経由でクロスドメインPOSTリクエストを送信するにはどうすればよいですか?

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


これを試すことができるユースケースについて少し知りたいのですが。何か教えていただけますか?
mkoeller 2008年

基本的に私は、HTMLファイルから別のサーバーにテキストを送信して処理する必要があるスクリプトに取り組んでいます。
Ido Schacham、2008年

3
サーバー側でこれを行い、スクリプトに結果を与えるだけのプロキシを設定できますか?それとも100%JavaScriptである必要がありますか?
サーシャチェディゴフ2009

回答:


382

更新:続行する前に、CORSのhtml5rocksチュートリアルを読んで理解してください。理解しやすく、非常に明確です。

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

つまり、from.com / 1.htmlからto.com/postHere.php(例としてPHPを使用)へのクロスドメインPOSTを実行する方法を以下に示します。注:Access-Control-Allow-OriginNON 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 " から発信された場合、POST | GET | ORIGINへのOKをブラウザーに通知します。サーバーはそれで問題ないので、ブラウザーは2番目の要求を行います(今回はPOST)。クライアントが送信するコンテンツタイプを設定することをお勧めします。そのため、これも許可する必要があります。

MDNには、HTTPアクセス制御に関する優れた記事があり、フロー全体のしくみについて詳しく説明しています。彼らのドキュメントによれば、「クロスサイトXMLHttpRequestをサポートするブラウザで動作する」はずです。私は、これは、しかし、少し誤解を招くですTHINKだけ現代のブラウザは、クロスドメインのPOSTを可能にします。私はこれがサファリ、クロム、FF 3.6でのみ動作することを確認しました。

この場合、次の点に注意してください。

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

たとえば、htmlを返すことができますか?HTMLを返す必要がありますが、何かが機能しません...
denis_n

いや、あなたはできるはずです。それを試したことがありません。サーバーは200を返しますか?また、サーバーはOPTIONS AND POSTリクエストのヘッダーを返しますか?これについてより詳細に回答を更新しました。サーバーが正しいcontent-typeヘッダー(text / htmlなど)で応答していることを確認してください。私の推奨は、Google Chromeを使用することです。ページを右クリックし、要素を検査します。ネットワークタブをクリックし、POSTと応答を監視します。何が問題なのかについての情報を提供する必要があります。
rynop

私はこれを試してみましたが、まだ取得している400 Bad RequestOPTIONS要求。そして、でfirefoxの、第2の要求POSTなされることはありません。:(
Zain Shaikh

上記のケースステートメントでローカルマシンを呼び出す方法はありますか?または、この場合は許可元に*を使用する必要がありますか?
トッドヴァンス

1
これは4年前に最後に編集されました-これはモバイルブラウザで動作しますか?
フランクピント2017

121

リモートサーバーを制御している場合は、この回答で説明されているように、おそらくCORSを使用する必要があります。IE8以降、およびFF、GC、Safariの最近のすべてのバージョンでサポートされています。(ただし、IE8とIE 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期間の応答を読み取ることができません。そうしないと、セキュリティ上の問題が発生します。


2
form.targetを何かに設定する必要があります。そうしないと、ブラウザがサイトからフォームアクションURLに移動します。さらに、文字列は一意である必要があります。同じ名前を使用する他のフレームまたはウィンドウがある場合、フォームはiframeではなくそのウィンドウにポストする可能性があります。しかし、それはどれほどユニークでなければなりませんか?おそらくそれほどではない。強盗の確率はかなり小さいです。肩をすくめる
Dan Fabulich

1
@Nawaz私の回答で述べたように、Webページで結果を取得するには、クロスドメインクロスフレーム通信を行う必要があります。リモートWebサーバーを制御して、その応答を変更してWebページと通信できるようにする必要があります。(1
つには

1
+1-これは、サーバーにアクセスできない場合に私が見つけた最良のソリューションです
James Long

1
@VojtechBいいえ、それはセキュリティホールになります。
Dan Fabulich 14

1
@Andrus POSTの結果を読み取ることができますが、サーバーを制御している場合のみです。その答えを見ると、「送信者[クライアント]でXを行い、受信者[サーバー]でYを行う」と書かれています。レシーバー/サーバーを制御しないと、Yを実行できないため、POSTの結果を読み取ることができません。
Dan Fabulich

48
  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のスタイルを設定し、非表示にして絶対配置する必要があります。ブラウザでクロスサイト投稿が許可されるかどうかはわかりませんが、許可されている場合は、これがその方法です。


4
実際、ifr.appendChild(frm);なので、これは少し不正確です。動作しないでしょう。iframeはウィンドウオブジェクトへの参照であり、そのためのappendChildメソッドは存在しません。最初にiframe内のドキュメントノードを取得する必要があります。ブラウザー間で機能するには、機能の検出が必要です。
Rakesh Pai

ありがとう。:問題に関するこれらの便利なリンクが見つかりbindzus.wordpress.com/2007/12/24/...の developer.apple.com/internet/webcontent/iframe.html
イドSchacham

19
問題!iframeで受信した応答は別のドメインにあるため、メインウィンドウはそれにアクセスできず、iframeもメインウィンドウにアクセスできません。このソリューションは、POSTを行うために良いと思われますが、その後応答を解析することはできません:(だから
イドSchacham

2
応答文字列で親の関数を呼び出すJavaScript関数への応答のbodyタグにonloadを設定してみてください。
ルーフランコ

この答えは私にはうまくいきませんでした。以下に自分のバリエーションを掲載しました。
Dan Fabulich、2011年

24

複雑にしないでおく:

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

  2. ページを更新するべきではありません:
    としてはありませんが、それはページを更新しませんsuccesserror非同期コールバックがときにサーバーのセンドバック応答と呼ばれます。


スクリプトの例:

$.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
        }
    });

8
crossDomain: true奇妙なことに、実際のクロスドメイン要求とはまったく関係ありません。リクエストがクロスドメインの場合、jqueryはこれを自動的にtrueに設定します。
Kevin B

16

関連するすべてのサーバーにアクセスできる場合は、他のドメインで要求されているページの応答のヘッダーに以下を入力します。

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;
}

これはおそらくセキュリティ上の問題を引き起こすので、要求を検証するために適切な手段を講じていることを確認する必要があります。



6
  1. 2つの非表示のiframeを作成します(CSSスタイルに「display:none;」を追加します)。2番目のiframeを自分のドメイン上の何かに向けます。

  2. 非表示フォームを作成し、そのメソッドをtarget = your first iframeで "post"に設定し、オプションでenctypeを "multipart / form-data"に設定します(画像のようなマルチパートデータを送信するため、POSTを実行したいと考えています?)

  3. 準備ができたら、フォームsubmit()をPOSTにします。

  4. 他のドメインがIframeとのクロスドメイン通信を行うJavaScriptを返すようにできる場合(http://softwareas.com/cross-domain-communication-with-iframes)、運が良ければ、応答をキャプチャできます。同様に。

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


6

注意すべきもう一つの重要なこと!!! ではは使用方法を説明しています上

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

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

コードを5時間テスト/調整しました。リモートサーバーに多数のヘッダーを追加する(スクリプト)。影響なし。しかし、後で、JQuery libを1.6.4に更新しました。すべてが魅力のように機能します。


Opera 10.61ではありません。これを行う最終的な決定は、私のドメインでPHPプロキシを使用することでした。
BasTaller 2012年

PHPプロキシをどのように使用しましたか?それについて教えてくれませんか?
Zoran777 2017年

以下の回答を参照してください。例:Ivan Durst
BasTaller

5

あなたはjQueryのAJAXとASP.net MVC環境でこれを実行したい場合は、次の手順を実行します(これはで提供されるソリューションの概要である。このスレッドで)。

「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
            }
        });

4

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

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)
}

stackoverflow.com/questions/38940932/…に関連する質問があります。サンプルに基づいてプラグインまたはジェネリック関数を作成することは可能ですか?
Andrus

@Andrusはおそらくこのようなものですgist.github.com/jcubic/26f806800abae0db9a0dfccd88cf6f3c
jcubic

このコードでは、レシーバーページを変更する必要があります。レシーバーページを変更できない場合の応答の読み方
Andrus

@Andrusあなたはajaxリクエストをそこに送るためにrecever.com iframeにアクセスする必要はありません。iframeがなければ、リクエストはありません。
jcubic

3

高レベル.... other-serve.your-server.comがother-server.comを指すように、サーバーにcnameを設定する必要があります。

ページは、other-server.comへのトランスポートとして機能する非表示のiframeを動的に作成します。次に、JSを介してページからother-server.comに通信し、データをページに返すコールバックを行う必要があります。

可能ですが、your-server.comおよびother-server.comからの調整が必要です


CNAMEを使用してリダイレクトすることさえ考えていませんでした。いいね!私はまだこれを試していませんが、CNAMEがブラウザをだまして同じサイトと対話していると思わせると思いますか?私はそれをAmazon S3への投稿に使用するので、これがうまくいくことを願っています。
SpencerElliott

1
これで何が解決されるかはわかりません。別のサブドメインへの移動には、別のドメインへの移動と同じ問題があります。
Octopus


2

これは古い質問ですが、新しいテクノロジーが誰かを助けるかもしれません。

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

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

http://github.com/digitalbazaar/forge


2

これは古い質問であることは知っていますが、私のアプローチを共有したいと思いました。私は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.');
}
});

1

YQLカスタムテーブル+ JS XHRで可能になるはずです。次を参照してください:http ://developer.yahoo.com/yql/guide/index.html

私はクライアント側(js)のHTMLスクレイピングを実行するためにそれを使用し、正常に動作します(インターネット/プレイリスト/歌詞/最後のfm情報、すべてのクライアントjs + YQLで検索できるフルオーディオプレーヤーを持っています)


1

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

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

そして、任意のオリジンがリクエストを送信できるようにする場合は、JSONPが必要です(Access-Control-Allow-Originも設定する必要がありますが、「*」にすることもできます)。

選択方法がわからない場合の多くのリクエスト方法では、それを行うには完全な機能コンポーネントが必要だと思います。シンプルなコンポーネントを紹介しましょうhttps://github.com/Joker-Jelly/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 <script>、HTMLのように、プロジェクトにインポートするすべての方法をサポートします。


1

クロスドメインサーバーにアクセスでき、サーバー側でコードを変更したくない場合は、「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要求をバイパスします。ライブラリは内部的に、資格情報とすべての可能なメソッド(GET、POSTなど)で機能するiframeソリューションを使用します。

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)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.