curl发送 JSON格式POST数据的接收,以及在yii2框架中的实现原理【精细剖析】 [ 技术分享 ]
Fecshop原文地址:curl发送 JSON格式POST数据的接收,以及在yii2框架中的实现原理【精细剖析】
1.通过curl发送json格式的数据,譬如代码:
<?php
function http_post_json($url, $jsonStr)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POSTFIELDS, $jsonStr);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json; charset=utf-8',
'Content-Length: ' . strlen($jsonStr)
)
);
$response = curl_exec($ch);
//$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return $response;
}
$api_url = 'http://fecshop.appapi.fancyecommerce.com/44.php';
$post_data = [
'username' => 'terry',
'password' => 'terry4321'
];
然后在接收端,使用$_POST
接收,发现打印是空的
原因是,PHP默认只识别application/x-www.form-urlencoded
标准的数据类型,因此接收不到,只能通过
//第一种方法
$post = $GLOBALS['HTTP_RAW_POST_DATA'];
//第二种方法
$post = file_get_contents("php://input");
来接收
2.如果我们在Yii2框架内,想通过
$username = Yii::$app->request->post('username');
$password = Yii::$app->request->post('password');
这种方式获取第一部分使用curl json方式传递的post参数,我们发现是不行的,我们需要设置yii2 request component
'request' => [
'class' => 'yii\web\Request',
'parsers' => [
'application/json' => 'yii\web\JsonParser',
],
],
然后我们通过
$username = Yii::$app->request->post('username');
$password = Yii::$app->request->post('password');
发现是可以取值的了,然后如果你打印 $_POST
,会发现这里依旧没有值,这是为什么呢?
下面我们通过代码顺藤摸瓜的查一下Yii2的源代码:
1.打开 yii\web\Request
找到post()方法:
public function post($name = null, $defaultValue = null)
{
if ($name === null) {
return $this->getBodyParams();
}
return $this->getBodyParam($name, $defaultValue);
}
发现值是由 $this->getBodyParam($name, $defaultValue)
给予
然后找到这个方法,代码如下:
/**
* Returns the request parameters given in the request body.
*
* Request parameters are determined using the parsers configured in [[parsers]] property.
* If no parsers are configured for the current [[contentType]] it uses the PHP function `mb_parse_str()`
* to parse the [[rawBody|request body]].
* @return array the request parameters given in the request body.
* @throws \yii\base\InvalidConfigException if a registered parser does not implement the [[RequestParserInterface]].
* @see getMethod()
* @see getBodyParam()
* @see setBodyParams()
*/
public function getBodyParams()
{
if ($this->_bodyParams === null) {
if (isset($_POST[$this->methodParam])) {
$this->_bodyParams = $_POST;
unset($this->_bodyParams[$this->methodParam]);
return $this->_bodyParams;
}
$rawContentType = $this->getContentType();
if (($pos = strpos($rawContentType, ';')) !== false) {
// e.g. application/json; charset=UTF-8
$contentType = substr($rawContentType, 0, $pos);
} else {
$contentType = $rawContentType;
}
if (isset($this->parsers[$contentType])) {
$parser = Yii::createObject($this->parsers[$contentType]);
if (!($parser instanceof RequestParserInterface)) {
throw new InvalidConfigException("The '$contentType' request parser is invalid. It must implement the yii\\web\\RequestParserInterface.");
}
$this->_bodyParams = $parser->parse($this->getRawBody(), $rawContentType);
} elseif (isset($this->parsers['*'])) {
$parser = Yii::createObject($this->parsers['*']);
if (!($parser instanceof RequestParserInterface)) {
throw new InvalidConfigException("The fallback request parser is invalid. It must implement the yii\\web\\RequestParserInterface.");
}
$this->_bodyParams = $parser->parse($this->getRawBody(), $rawContentType);
} elseif ($this->getMethod() === 'POST') {
// PHP has already parsed the body so we have all params in $_POST
$this->_bodyParams = $_POST;
} else {
$this->_bodyParams = [];
mb_parse_str($this->getRawBody(), $this->_bodyParams);
}
}
return $this->_bodyParams;
}
打印 $rawContentType = $this->getContentType();
这个变量,发现他的值为:
application/json
, 然后查看函数getContentType()
public function getContentType()
{
if (isset($_SERVER['CONTENT_TYPE'])) {
return $_SERVER['CONTENT_TYPE'];
}
if (isset($_SERVER['HTTP_CONTENT_TYPE'])) {
//fix bug https://bugs.php.net/bug.php?id=66606
return $_SERVER['HTTP_CONTENT_TYPE'];
}
return null;
}
也就是 当我们发送json格式的curl请求, $_SERVER['CONTENT_TYPE'] 的值为 application/json
2.重新回到上面的函数 getBodyParams()
,他会继续执行下面的代码:
if (isset($this->parsers[$contentType])) {
$parser = Yii::createObject($this->parsers[$contentType]);
if (!($parser instanceof RequestParserInterface)) {
throw new InvalidConfigException("The '$contentType' request parser is invalid. It must implement the yii\\web\\RequestParserInterface.");
}
$this->_bodyParams = $parser->parse($this->getRawBody(), $rawContentType);
}
$parser 就是根据我们下面的request component配置中的 parsers中得到'yii\web\JsonParser',进而通过容器生成出来的
'request' => [
'class' => 'yii\web\Request',
'enableCookieValidation' => false,
'parsers' => [
'application/json' => 'yii\web\JsonParser',
],
],
因此返回值就是 $parser->parse($this->getRawBody(), $rawContentType);
返回的,
3.首先我们查看传递的第一个参数是函数 $this->getRawBody()
,代码如下:
public function getRawBody()
{
if ($this->_rawBody === null) {
$this->_rawBody = file_get_contents('php://input');
}
return $this->_rawBody;
}
通过这个函数,回到前面我们说的,可以通过
//第一种方法
$post = $GLOBALS['HTTP_RAW_POST_DATA'];
//第二种方法
$post = file_get_contents("php://input");
这两种方式获取curl json传递的json数据,yii2使用的是第二种。
然后我们打开yii\web\JsonParser
/**
* Parses a HTTP request body.
* @param string $rawBody the raw HTTP request body.
* @param string $contentType the content type specified for the request body.
* @return array parameters parsed from the request body
* @throws BadRequestHttpException if the body contains invalid json and [[throwException]] is `true`.
*/
public function parse($rawBody, $contentType)
{
try {
$parameters = Json::decode($rawBody, $this->asArray);
return $parameters === null ? [] : $parameters;
} catch (InvalidParamException $e) {
if ($this->throwException) {
throw new BadRequestHttpException('Invalid JSON data in request body: ' . $e->getMessage());
}
return [];
}
}
可以看到这里是将传递的json转换成数组,然后Yii::request->post('username')就可以从返回的这个数组中取值了
总结:
1.在Yii2框架中要用封装的post() 和 get()方法, 而不要使用$_POST $_GET等方法,因为两者是不相等的。
2.Yii2做api的时候,如果是json格式传递数据,一定不要忘记在request component中加上配置:
'request' => [
'class' => 'yii\web\Request',
'parsers' => [
'application/json' => 'yii\web\JsonParser',
],
],
本文由 Terry 创作,采用 知识共享署名 3.0 中国大陆许可协议 进行许可。 可自由转载、引用,但需署名作者且注明文章出处。
共 2 条回复
-
Fecshop 全称为Fancy ECommerce Shop,是基于php Yii2框架之上开发的一款优秀的开源电商系统,
Fecshop支持多语言,多货币,架构上支持pc,手机web,手机app,和erp对接等入口,您可以免费快速的定制和部署属于您的电商系统。详细参看地址:Fecshop介绍
Fecshop 官网:http://www.fecshop.com ,您可以在这里提交bug,问题咨询等等。
Fecshop 【已完成】PC Web Demo :http://fecshop.appfront.fancyecommerce.com/
Fecshop 【已完成】Mobile Web Demo(WAP):http://fecshop.apphtml5.fancyecommerce.com
Fecshop 【已完成】Mobile VUE Demo(Appserver,前后端彻底分离模式):http://demo.fancyecommerce.com/#/
Fecshop 后台演示地址:加QQ群,在群公告里面有后台演示地址,账号密码等信息
Fecshop QQ群:186604851 ,入群验证:fecshop
Fecshop 作者QQ:2358269014
FecShop Email:2358269014@qq.com
Fecshop Github地址: https://github.com/fancyecommerce/yii2_fecshop
开源协议:Fecshop 授权协议
Fecshop 深圳
最后登录:2024-08-13
在线时长:73小时36分
- 粉丝157
- 金钱2381
- 威望490
- 积分8011