简单的JSONP& PHP示例不起作用

时间:2013-08-01 10:44:36

标签: php jsonp

尝试创建一个简单的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'}并将?callback = process直接放入$ .getJSON()网址时,为什么它不起作用?

  • 如果我使用<script src="http://server/server.php?callback=process"></script>代替$ .getJSON()调用,为什么它不起作用?

两个非工作案例实际上都返回process("It works");但是这没有被执行,为什么?

由于

1 个答案:

答案 0 :(得分:5)

这里有两个不同的问题,答案不同


当您使用$.getJSON()并将回调的名称字面上放在URL中时它不起作用的原因是因为jQuery的工作方式。

首先让我们看一下jQuery如果检测到你的$.getJSON()调用期望JSONP,如果你没有在设置对象中明确地传递任何明确的选项 - uses这个正则表达式:

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

这明确地查找查询字符串中的=?或仅包含单个?的查询字符串 - 实质上,检测URL将返回JSONP时需要问号。

没有它,jQuery使用XHR发出Ajax请求,服务器返回正确的数据。接下来会发生什么取决于同源策略。如果像您显示的代码一样,服务器通过Access-Control-*标头指示允许请求,那么数据将是可访问的,只要它是对客户端的源服务器的Ajax请求。如果这些标头不存在,则客户端代码将无法访问返回的数据。

但是,至关重要的是,因为它只是制作标准的Ajax请求并且没有向DOM添加<script>元素,这意味着响应文本永远不会被评估为Javascript代码 - 这是关键的最后一步JSONP机制。


第二个版本回答起来有点棘手,并且知道答案对所提供的信息是正确的,但是对于上面显示的HTML布局,我有理由相信这是原因:您的HTML元素是在错误的订单。

在页面加载时处理DOM时,处理在每个<script>元素处停止,同时相关的Javascript被同步加载和处理。这是为了确保所有Javascript按照预期的顺序执行,并确保以特定位置方式直接修改DOM的任何调用 - 例如document.write()(您应该从不如果您不知道的话,请使用 - 得到正确的尊重。

这样做的结果是,如果您在<script>标记之前将<p id="result">元素放在DOM 中,那么结果标记实际上并不存在于调用process()函数的点。并且因为您使用了jQuery选择器而不是document.getElementById(),所以如果您尝试直接修改它,则会吞下可能导致的错误。

这就是许多Javascript开发人员(包括我自己)现在告诉您应该将<script>标记作为<body>中最后一个元素的原因,因为它可以提高感知性能 - 尽管实际上加载和处理所有页面资源所需的网络时间完全相同,但它允许浏览器更快地呈现页面。这样做也无需使用$(document).ready() / DOMContentLoaded事件来延迟执行(顺便提一下,这也会解决这个问题,但是会稍微麻烦一点)。