使用contentType: 'application/json'的Ajax调用无法正常工作

14

我有一个ajax调用,将表单数据发送到php函数。由于我读到很多使用contentType: 'application/json'是最佳实践,所以我也想试试。但不幸的是,当我使用它时,我的脚本没有返回任何值。如果我将其删除,则脚本会按预期运行。

您是否有任何想法原因可能是什么以及为什么?谢谢!

$('#Form').submit(function(e) {
            e.preventDefault();

            var content = $(this).serialize() + "&ajax=1";

            $.ajax('app/class/controller/contactForm.php', {
              type: "POST",
              //contentType: 'application/json',
              dataType: 'json',
              data: content,
              success: function(result) {
                  console.log(result);
              }
            });
        })

以及我的 PHP:

if(isset($_POST['ajax']) && $_POST['ajax'] === '1') {
    echo json_encode(validateForm($_POST));
}

如果它能够正常工作,你为什么要加上它呢? - adeneo
类似的问题:http://stackoverflow.com/questions/17194251/no-response-from-generic-handler - Musa
1
contentType 指定您正在发送的数据格式,而不是接收的数据格式。您发送数据的格式是普通的查询字符串格式。 - Felix Kling
3个回答

24

使用contentType: 'application/json'时,您将无法依赖于$_POST被填充。 $_POST仅适用于表单编码的内容类型。

因此,您需要像这样从PHP原始输入中读取数据:

$input = file_get_contents('php://input');
$object = json_decode($input);
当然,如果您想发送 application/json,那么您应该发送 JSON 数据,但是您没有这样做。您需要直接将对象序列化为 JSON,或者像这样做 - 使用 jQuery 将表单数据转换为 JavaScript 对象 - 以序列化表单中的对象。 老实说,在您的情况下,由于您正在处理表单数据,我不认为有必要使用 application/json

谢谢!我猜这就是问题的根源。我看到一些例子中表单数据被序列化并设置了contentType,所以我认为应该是这样的。 - Sebsemillia
当然,如果您想使用 JSON 进行开发,PHP 没有任何理由不能响应 JSON。 它实际上可能取决于您在 JavaScript 中可用的方式,以确定您想如何 POST 到 PHP 并处理数据。例如,如果您有一个很好的 JavaScript 对象要 POST 到 PHP。将其序列化为 JSON 并使用“application/json”发送将非常简单,以便 PHP 可以轻松解码该对象并处理它。 - Mike Brant
感谢您解释$_POST未被填充的问题。这正是我正在寻找的信息。 - Sarah
你的回答帮了我很大的忙,经过数小时的寻找,我发现数据已经是JSON格式,所以不需要使用json_encode,而是需要使用json_decode进行解码。这是我的代码:$rawPostData = file_get_contents('php://input'); $json = json_decode($rawPostData); - Sarah

3

你所提到的最佳实践是关于服务器脚本将JSON的Content-Type设置为"application/json":

Header('Content-Type: application/json; charset=UTF8');

这是因为否则会发送默认的Content-Type,通常是一个万能的text/html,这可能会导致客户端无法理解。
如果您在jQuery请求中指定Content-Type,则jQuery将确定最合适的Content-Type。问题在于您正在发送一个POST表单,对于该表单,jQuery设置的默认Content-Type是application/x-www-form-urlencoded,告诉PHP将数据解码为POST字段并填充$_POST。然后您的脚本将从$_POST(或者也可能是$_REQUEST)中恢复其参数。
通过将其更改为application/json,$_POST将不再被填充,接收脚本操作将无法在预期位置接收参数,操作将中断。
因此,您需要:
  • 不要自己指定Content-Type(更好,个人意见)
  • 将Content-Type设置为application/x-www-form-urlencoded; charset=UTF-8
  • 将Content-Type设置为application/json; charset=UTF-8并修改脚本以解析POST流和解码JSON数据;请参见this answer

第三种选项需要正确处理php://inputproper handling


我明白了,这可能是问题所在。非常感谢! - Sebsemillia
@Isemi 关于内容类型的评论是正确的。您关于不设置Content-Type标头的信息是不正确的。大多数HTTP通信都应该设置此设置。这只是让接收客户端知道数据发送的格式。在向服务器发出AJAX调用的情况下,服务器是接收客户端。浏览器绝对应该设置Content-Type标头,以便服务器知道要期望什么。在这种情况下,因为正在发生这种情况,服务器期望JSON,并且不会像对待表单编码的Content-Type一样构建$ _POST - Mike Brant
同样地,当服务器向JavaScript客户端发送其响应时,它应该设置Content-Type头,就像您建议的那样。这告诉浏览器客户端可以期望什么格式。因此,总结一下,Content-Type应该在客户端到服务器调用和服务器到客户端响应中都声明。 - Mike Brant
@MikeBrant,是的,我意识到这些问题了;我的回答措辞不当。即使我正在为您点赞,也会更新答案 :-) - LSerni
非常感谢。您提供的关于“正确处理php://input”的链接,在我寻找了数小时后,终于解决了我的问题。 :) - Sarah

2
PHP脚本应设置Content-Type头部。
if(isset($_POST['ajax']) && $_POST['ajax'] === '1') {
    header('Content-Type: application/json');
    echo json_encode(validateForm($_POST));
}

嗯,不幸的是它仍然不能运行。我只得到了一个空的响应。 - Sebsemillia
你说得没错,PHP脚本应该发送这样的头部信息,但这与问题无关。问题在于,通过将application/json设置为初始AJAX调用到PHP的内容类型,PHP没有构建$_POST。此外,还存在一个问题,他根本没有发送JSON,而是发送了一个URL编码的查询字符串,就像使用典型的表单编码POST一样。 - Mike Brant

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接