houheaven
houheaven
  • 发布:2017-12-13 17:20
  • 更新:2017-12-13 17:20
  • 阅读:4285

XMLHttpRequest 发送 post 请求,php 接收不到数据的解决方案

分类:HTML5+

.

说明

这是我入门 DC(DCloud)遇到的第一个比较正式的问题。
我是一名前端开发者,同时也会点世界最好的编程语言 php(开个玩笑,别动手)。
当然 php 只是作为我的辅助技能,方便自己调试用,当然在与后台配合做项目时也会得心应手,所以,在入门学习 XMLHttpRequest 自己调试的时候,发现 php 接收不到 post 请求的参数,然后就在问答社区和度娘找原因,几经周折,完美的解决了这个问题。

.

php 接收不到数据的根本原因是什么?

前端发送数据的 "编码方式" 与后台接收数据的 "解码方式" 不同。
这里说的编码与解码对应的是请求头 header 中的 Content-Type 字段。

Content-Type 的主要方式:

  • text/xml (xml 数据格式)
  • text/html (html 数据格式)
  • text/plain (无格式字符串数据格式)
  • multipart/form-data (上传文件)
  • application/json (json 数据格式)
  • application/x-www-form-urlencoded (序列化数据 / url 查询地址,比如 name=Eric&password=123456)

.
第一个、第二个,因为我至今没接触过,不敢多言。
第三个,无格式字符串数据格式,就是很普通的字符串。
第四个,是 form 表单上传文件时用的,这里暂时也不讨论这个。
第五个和第六个,是我要具体要讨论的。

PS:这个月的膝盖献给这位大神:四种常见的 POST 提交数据方式

.

方案一:Content-Type: "application/json"

首先,我们先看下,XMLHttpRequest 请求头的默认编码方式是什么。

JS 部分

var xhr = new plus.net.XMLHttpRequest();  
xhr.onreadystatechange = function()  
{  
    if( xhr.readyState==4 && xhr.status==200 )  
    {  
        console.log(xhr.responseText);  
    }  
}  
var json = {  
    name: "Eric",  
    password: "123456"  
};  
xhr.open("POST","http://www.xxx.com/api.php");  
xhr.send(JSON.stringify(json));  // post 数据只能是字符串  

PHP 部分

<?php  
    // 返回请求头的编码方式和 name 的值  
    $header = $_SERVER["CONTENT_TYPE"];  
    $name = $_POST["name"];  
    echo '{"header":"'.$header.'","name":"'.$name.'"}';  
?>  

返回结果:{"header":"text/plain;charset=utf-8","name":""}
很显然,$_POST["name"] 没有取到数据。

后来,我看到了这篇文章:Mui v3.2.0中ajax设置headers为{'Content-Type': 'application/json'}发起post请求,后端接收不到数据的解决方案(php为例)
虽然他说的是 mui.ajax 方式,但是思路都是一样的,然后,我修改了下代码。

JS 部分

var xhr = new plus.net.XMLHttpRequest();  
xhr.onreadystatechange = function()  
{  
    if( xhr.readyState==4 && xhr.status==200 )  
    {  
        console.log(xhr.responseText);  
    }  
}  
var json = {  
    name: "Eric",  
    password: "123456"  
};  
xhr.open("POST","http://www.xxx.com/api.php");  
xhr.setRequestHeader("Content-Type","application/json;charset=utf-8");  
xhr.send(JSON.stringify(json));  // post 数据只能是字符串  

PHP 部分

<?php  
    // 返回请求头的编码方式和 name 的值  
    $input = file_get_contents('php://input');  
    $object = json_decode($input);  
    $name = $object->name;  
    echo '{"header":"'.$_SERVER["CONTENT_TYPE"].'","name":"'.$name.'"}';  
?>  

返回结果:{"header":"application/json;charset=utf-8","name":"Eric"}
很显然,数据已经接收到,这种方案确实有效。

虽然确实能解决问题,但我最终没有采用的原因是:
①. 不够直接,它不是通过 $_POST[] 方式获取的数据,后台需要对数据进行解析,无形中增加了工作量
②. 旧项目迁移不友好,如果旧项目之前采用的是 $_POST[] 方式,后台接口改动会很大

.

方案二:Content-Type: "application/x-www-form-urlencoded"

首先,后台(php)使用 $_POST[] 获取数据,需要满足两个条件:

  • 设置请求头,Content-Type: "application/x-www-form-urlencoded"
  • 请求数据必须序列化,比如,name=Eric&password=123456

直接上代码:

JS 部分

var xhr = new plus.net.XMLHttpRequest();  
xhr.onreadystatechange = function()  
{  
    if( xhr.readyState==4 && xhr.status==200 )  
    {  
        console.log(xhr.responseText);  
    }  
}  
xhr.open("POST","http://www.xxx.com/api.php");  
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded;charset=utf-8");  
xhr.send("name=Eric&password=123456");  

PHP 部分

<?php  
    $header = $_SERVER["CONTENT_TYPE"];  
    $name = $_POST["name"];  
    echo '{"header":"'.$header.'","name":"'.$name.'"}';  
?>  

返回结果:{"header":"application/x-www-form-urlencoded;charset=utf-8","name":"Eric"}

至此,问题已解决,而且不需要后台程序的特殊处理。
但是,现在的方案却不完善,因为大部分情况,我们发送的 POST 请求数据是 JSON 对象,这时候 PHP 仍然获取不到数据,此时的我,脑海中响起了《西游记》的一首歌:刚翻过了几座山,又越过了几条河,崎岖坎坷怎么它就这么多 。。

后来,我问了下度娘,它告诉我,只需要一行代码就可以将 JSON 对象转换成序列化数据。
那就是 jquery 的这个功能:$.param(JSON)

JS 部分

var xhr = new plus.net.XMLHttpRequest();  
xhr.onreadystatechange = function()  
{  
    if( xhr.readyState==4 && xhr.status==200 )  
    {  
        console.log(xhr.responseText);  
    }  
}  
var json = {  
    name: "Eric",  
    password: "123456"  
};  
xhr.open("POST","http://www.xxx.com/api.php");  
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded;charset=utf-8");  
xhr.send($.param(json));  

多谢万能的 jquery 霸霸。
至此,这个问题就被彻底地解决了,呕吼,略略略略略略略略 。

.

适用场景

综上,这个方案适用于 PHP 使用 $_POST[] 的方式来获取 post 请求数据的场景。
希望对你有帮助。

.

1 关注 分享
442774948@qq.com

要回复文章请先登录注册