我正在尝试将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中处理?
借用了一些代码:Sending a JSON to server and retrieving a JSON in return, without JQuery
以下是一些相关问题: Code to be run twice in Ajax request, Running curl twice in php, https://stackoverflow.com/questions/24373623/ajax-request-help-code-gets-created-twice, Ajax form submitting twice with Yii 2
这个问题(这里投票最高的一个)当然是相关的,但是对于为什么PHP代码运行两次没什么可说的:
答案 0 :(得分:0)
您的javascript代码中存在一些语法错误(如缺少括号)。您还应该使用“var”来声明变量以将范围限制为函数。也许这会导致这种奇怪的行为。在更正javascript代码后,我无法重现您提到的错误=&gt;只要一个错误日志条目,无论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方法是否为“OPTIONS”请求=&gt;如果是这样,只需返回标题。
关于缓存问题:您可以通过“Access-Control-Max-Age”标题将预检缓存期限设置为零。
以下是应该有效的整个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;
}
?>
答案 1 :(得分:0)
我发布了这个答案,但解决这个问题的人实际上是Roman Shtylman,请查看他今天关于CORS预检here的评论(2015-01-13)。
规则似乎是如果您使用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/
如果实际发生缓存是另一个问题。我完全不知道这个问题的答案。 : - (