意外的PHP/jQuery/JSON交互差异


Unexpected PHP/jQuery/JSON interaction differences

背景:

因此,我编写了以下PHP代码片段来帮助我调试一个更大的问题,但现在我更困惑于jQuery和PHP如何发送/接收JSON,因为这段代码似乎没有达到我的预期:

我希望能够接收数据作为application/x-www-form-urlencoded作为application/json,同时仅使用application/json进行响应(目前)。

test.php:

<?php
$content_type = $_SERVER['CONTENT_TYPE'];
switch ($_SERVER['REQUEST_METHOD']) {
    case 'GET':
        echo <<< _EOF
<html>
<body>
<div id="content"></div>
<script type="text/javascript" src="/jquery-1.10.2.min.js"></script>
</body>
</html>
_EOF;
        break;
    case 'POST':
        header('Content-type: application/json');
        if ($content_type == 'application/x-www-form-urlencoded') {
            $_POST['message'] = 'debugged';
            echo json_encode($_POST);
        # Otherwise, get raw body data.
        } else {
            $data = file_get_contents('php://input');
            if ($data == null) {
                $data = file_get_contents('php://stdin');
            }
            $object = json_decode($data, true);
            $object['message'] = 'debugged';
            echo json_encode($object);
        }
        break;
    default:
        echo "These aren't the droids you're looking for. Move along.<br />";
        break;
}

测试:

我一直在使用Python请求库和jQuery的Ajax方法测试这段代码。

在Python中,数据可以作为application/x-www-form-urlencoded发送,也可以作为附加到请求的原始主体数据发送,具体取决于为post()方法提供的data参数的类型(有关更多信息,请参阅此处)。

到目前为止一切顺利

使用请求,我得到了我所期望的。

post()方法的data参数是Python字典对象时,数据以编码形式发送:

>>> import requests
>>> r = requests.post('http://example.com/test.php', data={"name": "tester", "message": "bug"})
>>> print r.text
{"message": "debugged", "name": "tester"}

data参数是文本字符串(注意单引号!)时,数据将作为请求的主体发送,并且可能(也可能不)在端点被解释为JSON(我在上面的示例PHP代码中确实将其解释为JSON,并且保证它永远只是JSON):

>>> r = requests.post('http://example.com/test.php', data='{"name": "tester", "message": "bug"}')
>>> print r.text
{"message": "debugged", "name": "tester"}

这两个结果都是我所期望的。

这是奇怪的部分

我似乎从这段代码中得到了不同的响应,这并不取决于我如何发送数据,而是我用什么发送数据(即请求或jQuery)。这两者之间一定有什么不同之处,我完全不知道。

如果我将浏览器(Chrome)指向http://example.com/test.php,触发GET请求处理程序为我提供上面PHP代码中包含的微小HTML页面,然后在JavaScript控制台中启动以下jQuery代码,这就是我得到的结果:

> var output = null;
> $.ajax({
      type: 'POST',
      url: 'http://example.com/test.php',
      data: {
          name: 'tester',
          message: 'bug'
      },
      dataType: 'json',
      beforeSend: function(x) {
          if (x && x.overrideMimeType) {
              x.overrideMimeType('application/json; charset=UTF-8');
          }
      },
      success: function(d) {
          $output = d;
      }
  });
> output
Object {message: "debugged"}

现在我在想,"名字"条目到底去了哪里

事实证明,只有我在PHP处理程序中显式设置的东西似乎可以作为jQuery的输出访问。但有时我想使用来自用户输入的数据,对其进行修改,然后将其作为输出返回。但由于jQuery的行为是这样的,(或者PHP……我不太确定我的错误在哪一段代码中)我无法做我想做的事情。

更奇怪

我做的下一件事是根据POST处理程序中的if语句是输入的还是"elsed",将输出消息更改为"debugged(表单数据)"或"debuggeed(主体数据)",并惊讶地发现jQuery将数据作为主体数据发送,但正在设置application/x-www-form-urlencoded标头这完全不是我所期望的。我觉得jQuery(1.10.2)或Python请求中的任何一个都因为这种差异而行为不端,但我不确定是哪一个。(或者发送表单编码的数据真的是这种特殊的吗?)

如果对这里发生的事情有任何想法或见解,我错过了什么,如果我的期望或错误,我应该期待什么,甚至是我在研究这件事时忽略的相关文档的链接,我们将不胜感激。

是否尝试将标识符"name"置于引号中。这是一个保留字,有些解析器无法很好地处理它不在引号中的问题。几年前我也遇到过类似的问题。