为什么 ajax 'application/json' 要运行 PHP 代码两次

Why do an ajax `application/json` run PHP code twice?

本文关键字:代码 PHP 两次 application ajax json 为什么 运行      更新时间:2023-09-26

我正在尝试将JSON数据从JavaScript发布到PHP。您可以使用任一方式执行此操作

Content-Type: application/json

Content-Type: application/x-www-form-urlencoded

两者都有效,但我很难让第一个工作。原因是我错过了内容类型为 application/json 时 PHP 脚本似乎运行了 2 次。

我很惊讶,想知道发生了什么。谁能解释一下发生了什么以及如何处理它?(有一些相关的问题,但似乎没有一个答案观察到这种行为。

这是我的测试代码。首先启动PHP内置服务器:

php.exe -S localhost:7000

然后在该目录中使用以下代码创建文件test1.php

<?php
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: Content-Type");
header("Content-Type: application/json");
function writeStdErr($msg) { $fh = fopen('php://stderr','a'); fwrite($fh, $msg); fclose($fh); }
writeStdErr("'n'nI am here!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'n");
$e = stripslashes(file_get_contents("php://input"));
writeStdErr("e=".$e."'n");
if (strlen($e) > 0) echo $e;

现在从网络浏览器控制台(我正在使用谷歌浏览器)进行ajax调用:

function test1(j) {
    url = "http://localhost:7000/test1.php";
    type = "application/x-www-form-urlencoded";
    if (j) type = "application/json";
    xhr = new XMLHttpRequest();
    xhr.open("POST", url, true);
    xhr.setRequestHeader("Content-type", type);
    xhr.addEventListener("readystatechange", function () { 
        if (xhr.readyState == 4 && xhr.status == 200) {
            var json = JSON.parse(xhr.responseText);
            console.log(json.email + ", " + json.password)
        }
    });
    var data = JSON.stringify({"email":"hey@mail.com","type":type});
    xhr.send(data);
    console.log("now sending >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>", url, type);
}
test1(false) 

控制台中的输出正是我所期望的:

I am here!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
e={"email":"hey@mail.com","type":"application/x-www-form-urlencoded"}

现在改为使用 applicaion/json 进行 ajax 调用,即 test1(true) .输出现在为:

I am here!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
e=
I am here!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
e={"email":"hey@mail.com","type":"application/json"}

如您所见,PHP 代码已经运行了两次。第一次没有输入php://input.

为什么???这应该如何在 PHP 中处理?


在这里借用了一些代码:将 JSON 发送到服务器并检索 JSON 作为回报,没有 JQuery

以下是一些相关问题:要在 Ajax 请求中运行两次的代码,在 php 中运行卷曲两次,https://stackoverflow.com/questions/24373623/ajax-request-help-code-gets-created-twice,使用 Yii 2 提交两次 Ajax 表单

这个问题(这里投票最高的问题之一)当然是相关的,但没有什么可说的,为什么PHP代码运行两次:

正确的 JSON 内容类型是什么?

我发布了这个答案,但解决这个问题的人实际上是Roman Shtylman,请看他今天(2015-01-13)对CORS飞行前的评论。

规则似乎是,如果您使用 application/x-www-form-urlencode,则没有 CORS 预检,但如果您使用 application/json 就有:

https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS

因此,如果使用"错误"标头(即 application/x-www-form-urlencode),然后有人建议:

https://remysharp.com/2011/04/21/getting-cors-working

但。。。然后是缓存:

http://www.html5rocks.com/en/tutorials/cors/

如果这种缓存真的发生是另一个问题。我完全不知道这个问题的答案。:-(

你的javascript代码中有一些语法错误(比如缺少括号)。此外,您应该使用"var"来声明变量以将范围限制为函数。也许这会导致这种奇怪的行为。更正 javascript 代码后,我无法重现您提到的错误 => 无论 test1 的参数设置为 true 还是 false,我都只有一个错误日志条目。

这是更正后的代码 - 试一试:

function test1(j) {
    var url = "http://localhost:7000/test1.php";
    var type = "application/x-www-form-urlencoded";
    if (j) {
        type = "application/json";
    }
    var xhr = new XMLHttpRequest();
    xhr.open("POST", url, true);
    xhr.setRequestHeader("Content-type", type);
    xhr.addEventListener("readystatechange", function () { 
            if (xhr.readyState == 4 && xhr.status == 200) {
                    var json = JSON.parse(xhr.responseText);
                    console.log(json.email + ", " + json.type)
            }
    });
    var data = JSON.stringify({"email":"hey@mail.com","type":type});
    xhr.send(data);
    console.log("now sending >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>", url, type);
}
test1(false);

编辑:

啊,对不起,我的错。我没有读到您从 javascript 控制台运行脚本。我将其嵌入到通过浏览器调用的 php 文件中。所以这不是一个跨域请求,这就是它对我有用的原因。

我现在能够重现您的问题。如您提供的链接中所述,您应该检查请求的 HTTP 方法是否是"选项"请求 =>如果是,只需返回标头。

关于缓存问题:您可以通过"访问控制最大期限"标头将预检缓存期限设置为零。

这是应该工作的整个 php 代码:

<?php 
    header("Access-Control-Allow-Origin: *");
    header("Access-Control-Allow-Headers: Content-Type");
    header("Content-Type: application/json");
    header("Access-Control-Max-Age: 0");
    if ($_SERVER['REQUEST_METHOD'] != 'OPTIONS') {
        function writeStdErr($msg) {
            $fh = fopen('php://stderr','a'); 
            fwrite($fh, $msg); 
            fclose($fh); 
        }
        writeStdErr("'n'nI am here!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'n");
        $e = stripslashes(file_get_contents("php://input"));
        writeStdErr("e=".$e."'n");
        if (strlen($e) > 0) echo $e;
    }
?>