3

単純な JSONP 呼び出しを作成しようとしましたが、常に機能するとは限らず、理由がわかりません。コードは次のとおりです。

サーバー側 ( http://server/server.php):

<?php
    $res = json_encode("It works!");

    if(isset($_GET['callback']) === TRUE) {
        header('Content-Type: text/javascript;');
        header('Access-Control-Allow-Origin: http://client');
        header('Access-Control-Max-Age: 3628800');
        header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE');
        echo $_GET['callback']."(".$res.");";
    } else {
        echo $res;
    }
?>

クライアント側 ( http://client/client.html):

<html>
    <head><title>JSONP</title></head>
    <body>
        <h1>JSONP Experiment</h1>
        <script src="http://code.jquery.com/jquery-latest.min.js"></script>
        <script>
            function process(data) {
                $('#result').text(data);
            }

            $.getJSON(
                'http://server/server.php?callback=?',
                {'callback': 'process'}
            );

        </script>
        <p id="result"></p>

    </body>
</html>

このコードは機能し、「It works!」と表示されます。私の中で

ブロック。

  • {'callback': 'process'}$.getJSON() URL に直接 ?callback=process を使用して配置しないと機能しないのはなぜですか?

  • <script src="http://server/server.php?callback=process"></script>$.getJSON() 呼び出しの代わりに使用すると機能しないのはなぜですか?

両方の動作しないケースが実際に返さprocess("It works");れますが、これは実行されません。なぜですか?

ありがとう

4

1 に答える 1

5

ここには2つの異なる問題があり、異なる答えがあります


$.getJSON()コールバックの名前を文字通り URL に使用して配置すると機能しない理由は、jQuery の動作方法が原因です。

$.getJSON()最初に、設定オブジェクトでそれを明示的に示すオプションを渡さない場合に、呼び出しが JSONP を想定していることを jQuery がどのように検出するかを見てみましょう。次の正規表現が使用されます。

/(=)\?(?=&|$)|\?\?/

=?これは、クエリ文字列または 1 つだけで構成されるクエリ文字列のいずれかを明示的に検索します?。本質的に、URL が JSONP を返すことを検出するには、疑問符が必要です。

これがないと、jQuery は XHR を使用して Ajax リクエストを作成し、サーバーから正しいデータが返されます。次に何が起こるかは、Same Origin ポリシーによって異なります。あなたが示すコードのように、サーバーがAccess-Control-*ヘッダーを介してリクエストが許可されていることを示している場合、クライアントのオリジンサーバーへのAjaxリクエストと同じように、データにアクセスできます。これらのヘッダーが存在しない場合、返されたデータはクライアント コードからアクセスできません。

しかし、これは標準の Ajax リクエストを作成するだけで、<script>要素を DOM に追加しないため、JSONP メカニズムの重要な最終ステップである Javascript コードとして評価されることはありません。


2 番目のバージョンは回答が少し難しく、提供された情報で回答が正しいことがわかりますが、上記の HTML レイアウトでは、これが理由であると確信しています: HTML 要素が間違った順序で定義されています。

ページの読み込み時に DOM を処理する場合<script>、関連する Javascript が同期的に読み込まれ、処理される間、すべての要素で処理が停止します。これは、すべての Javascript が意図した順序で実行されるようにするためです。また、DOM を場所固有の方法で直接変更するものへの呼び出しdocument.write()(たとえば、知らない場合は決して使用しないでください) が行われるようにするためです。正しく表彰されました。

この結果、タグの前に<script>要素を DOMに配置した場合、結果タグは関数が呼び出された時点に実際には存在しません。また、 の代わりに jQuery セレクターを使用したため、直接変更しようとした場合に発生したエラーを飲み込みます。<p id="result">process()document.getElementById()

<script>これが、多くの Javascript 開発者 (私自身を含む) が、タグを の最後の要素として配置する必要があると言う理由です<body>。実際にはまったく同じ量のネットワークが必要であるにもかかわらず、パフォーマンスが向上します。すべてのページ リソースを読み込んで処理するのに時間がかかるため、ブラウザはページをより速くレンダリングできます。$(document).ready()これを行うと、 /イベントなどを使用して実行を遅らせる必要もなくなりますDOMContentLoaded(ちなみに、これはこの問題も解決しますが、少し厄介な方法です)。

于 2013-08-01T11:34:55.253 に答える