JsonPへのデータの投稿


102

JsonPにデータを投稿することはできますか?または、すべてのデータをGETリクエストとしてクエリ文字列で渡す必要がありますか?

サービス、クロスドメインに送信する必要があるデータがたくさんあり、クエリ文字列を介して送信するには大きすぎる

これを回避するためのオプションは何ですか?

回答:


83

同じ生成元ポリシーPOSTの(かなり賢明な)制限のため、別のドメインのサービスに対して非同期にすることはできません。JSON-Pが機能するのは、DOMにタグを挿入することが許可されており、どこにでもタグを付けることができるためです。<script>

もちろん、別のドメインのページを通常のフォームPOSTのアクションにすることもできます。

編集:隠されたsを挿入し、そのプロパティをいじくり回すために多くの努力を惜しまない場合、興味深いハックがいくつかあり<iframe>ます。


「非同期POST」は不可能だとおっしゃっていましたが、同期POSTを実行できますか?
Mark

4
@mark "synchronous POST"は、<form method = "post" action = "http:// ... / ...">を使用するフォームを送信することを意味します
Steven Kryskalla

8
これは真実ではありません。POST他のドメインとブラウザの両方がサポートしている限り、他のドメインへのリクエストを確実に行うことができますCORS。しかし、それは完全に本当でPOSTありJSONP、互換性はありません。
ヒッピートレイル

2
JSONPは<script>、別のドメインを指すタグを挿入することで実装されます。ブラウザでPOSTリクエストを実行する唯一の方法は、HTMLフォームまたはXMLHttpRequestを使用することです。
フリード

1
(一般的に-)別のドメインのサービスに対して非同期POSTを実行することが可能です(!)。制限は応答にあります。制限はJSONPリクエストにもあります。
Royi Namir 2014

20

クロスドメインで大量のデータを送信する必要がある場合。私は通常、2つのステップで呼び出すことができるサービスを作成します。

  1. 最初に、クライアントはFORMサブミットを実行します(ポストクロスドメイン)。サービスは、入力をサーバーのセッションに格納します(GUIDをキーとして使用)。(クライアントはGUIDを作成し、それを入力の一部として送信します)

  2. 次に、クライアントは、FORMポストで使用したものと同じGUIDを使用するパラメーターとして、通常のスクリプト挿入(JSONP)を実行します。サービスはセッションからの入力を処理し、通常のJSONP形式でデータを返します。この後、セッションは破棄されます。

もちろん、これはあなたがサーバーバックエンドを書くことに依存しています。


1
あなたのアプローチを試みました。FF14とChrome20で働いていました。Opera11とIE9は投稿を転送しませんでした。(彼らのデバッグツールでそれをチェックし、もう一方の端にサーバーに耳を傾けて)たぶんIEの障害に関連するが、この質問です:stackoverflow.com/questions/10395803/...コンソールにクロームの苦情を、それでもPOSTをした:XMLHttpRequestのができませんload localhost:8080 / xxx Origin nullは、Access-Control-Allow-Originでは許可されていません。
OneWorld 2012

@OneWorld —あなたは答えが言ったことをしませんでした。XMLHttpRequestまったく関与すべきではありません。Perの回答は、通常のフォーム送信を使用してPOSTリクエストを作成し、次にスクリプト要素の注入を使用してGETリクエストを作成します。
クエンティン2014年

7

私はこれが深刻なネクロマンシーであることを知っていますが、私はjQueryを使用してJSONP POSTの実装を投稿すると思いました。

基本的に、受け入れられた回答で示唆されているように、私はIFrameアプローチを使用しています。私が別のことをしているのは、リクエストを送信した後、タイマーを使用してiframeでフォームに到達できる場合は監視しています。フォームにアクセスできない場合は、リクエストが返されたことを意味します。次に、通常のJSONPリクエストを使用して、操作のステータスをクエリしています。

私は誰かがそれが役に立つと思うことを望みます。IE8、Chrome、FireFox、Safariでテスト済み。

function JSONPPostForm(form, postUrl, queryStatusUrl, queryStatusSuccessFunc, queryStatusData)
{
    var tmpDiv = $('<div style="display: none;"></div>');
    form.parent().append(tmpDiv);
    var clonedForm = cloneForm(form);
    var iframe = createIFrameWithContent(tmpDiv, clonedForm);

    if (postUrl)
        clonedForm.attr('action', postUrl);

    var postToken = 'JSONPPOST_' + (new Date).getTime();
    clonedForm.attr('id', postToken);
    clonedForm.append('<input name="JSONPPOSTToken" value="'+postToken+'">');
    clonedForm.attr('id', postToken );
    clonedForm.submit();

    var timerId;
    var watchIFrameRedirectHelper = function()
    {
        if (watchIFrameRedirect(iframe, postToken ))
        {
            clearInterval(timerId);
            tmpDiv.remove();
            $.ajax({
                url:  queryStatusUrl,
                data: queryStatusData,
                dataType: "jsonp",
                type: "GET",
                success: queryStatusSuccessFunc
            });
        }
    }

    if (queryStatusUrl && queryStatusSuccessFunc)
        timerId = setInterval(watchIFrameRedirectHelper, 200);
}

function createIFrameWithContent(parent, content)
{
    var iframe = $('<iframe></iframe>');
    parent.append(iframe);

    if (!iframe.contents().find('body').length)
    {
        //For certain IE versions that do not create document content...
        var doc = iframe.contents().get()[0];
        doc.open();
        doc.close();
    }

    iframe.contents().find('body').append(content);
    return iframe;
}

function watchIFrameRedirect(iframe, formId)
{
    try
    {
        if (iframe.contents().find('form[id="' + formId + '"]').length)
            return false;
        else
            return true;
    }
    catch (err)
    {
        return true;
    }
    return false;
}

//This one clones only form, without other HTML markup
function cloneForm(form)
{
    var clonedForm = $('<form></form>');
    //Copy form attributes
    $.each(form.get()[0].attributes, function(i, attr)
    {
        clonedForm.attr(attr.name, attr.value);
    });
    form.find('input, select, textarea').each(function()
    {
        clonedForm.append($(this).clone());
    });

    return clonedForm;
}

4

通常、JSONPは<script>、JSONPサービスのURLが「src」になるように、呼び出し元のドキュメントにタグを追加することで実装されます。ブラウザは、HTTP GETトランザクションでスクリプトソースをフェッチします。

JSONPサービスが呼び出しページと同じドメインにある場合、おそらく単純な$.ajax()呼び出しで何かをまとめることができます。それが同じドメインにない場合、それがどのように可能になるかはわかりません。


この場合、同じドメインにはありません。そして、私は唯一のGETが可能であると仮定すると、私は今日だけ、それは私が必要なものに適しているかどうかについて、いくつかの意思決定を行うために必要JSONPについての読み取りを開始してきたようにチェックしたいのです
ChrisCa

2
同じドメインにはないがサポートしているCORS場合は、ブラウザもサポートしている限り可能です。これらのケースJSONでは、ではなくプレーンを使用しますJSONP
ヒッピートレイル

はい、@ hippietrail 2年間は大きな違いをもたらします:-) CORSはそれを可能にしますが、もちろん、データソースを適切に設定する必要があります。
先のとがった

0

このプロジェクトを使用してCORSプロキシを使用できます。すべてのトラフィックをドメインのエンドポイントに転送し、その情報を外部ドメインに中継します。ブラウザはすべてのリクエストを同じドメインに登録するため、JSONを投稿できます。 注:これは、サーバーに保持されているSSL証明書でも機能します。


-1

私が何度もやった(ハック)ソリューションがあります。JsonPで投稿できます。(GETで使用できるよりも2000文字を超えるフォームを投稿できます)

クライアントアプリケーションJavaScript

$.ajax({
  type: "POST", // you request will be a post request
  data: postData, // javascript object with all my params
  url: COMAPIURL, // my backoffice comunication api url
  dataType: "jsonp", // datatype can be json or jsonp
  success: function(result){
    console.dir(result);
  }
});

JAVA:

response.addHeader( "Access-Control-Allow-Origin", "*" ); // open your api to any client 
response.addHeader( "Access-Control-Allow-Methods", "POST" ); // a allow post
response.addHeader( "Access-Control-Max-Age", "1000" ); // time from request to response before timeout

PHP:

header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST');
header('Access-Control-Max-Age: 1000');

このようにして、サーバーを任意のPOSTリクエストに対して開きます。IDまたは何か他のものを提供することにより、これを再度保護する必要があります。

この方法では、リクエストタイプをjsonpからjsonに変更することもできます。どちらも機能し、適切なレスポンスコンテンツタイプを設定するだけです。

jsonp

response.setContentType( "text/javascript; charset=utf-8" );

json

response.setContentType( "application/json; charset=utf-8" );

あなたがサーバーであることはもはやSOP(同じ発信元ポリシー)を尊重しないことに注意してください。


これはCORSでのAJAXではありません。AJAXは、XMLを使用していることを意味します。これはCORSを使用したJSON [P]です。JSONPは「パディング」付きの「JSON」です。パディング用の関数呼び出しでラップされたJSONデータを送信している場合は、CORSを使用したJSONPです。<script>タグをHTML DOMに挿入するだけでなく、JSONとJSONPの両方のデータ表記を使用できます(たとえば、同じアプリに複数のJSONリクエストを作成し、関数名を使用したい場合は、デスクトップアプリでそれらを使用することもできます)たとえば、リクエスト追跡IDとして)。
BrainSlugs83 2014年

-6

可能です、これが私の解決策です:

あなたのjavascriptで:

jQuery.post("url.php",data).complete(function(data) {
    eval(data.responseText.trim()); 
});
function handleRequest(data){
    ....
}

あなたのurl.phpで:

echo "handleRequest(".$responseData.")";

11
この場合、jQueryはドキュメントに従って、おそらくリクエストをGetに変換しました。注:これにより、リモートドメインリクエストのPOSTがGETに変換されます。api.jquery.com/jQuery.ajax
OneWorld
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.