当前位置: 首页 > 后端技术 > PHP

PHPYii下$_REQUEST无法获取到前端post的数据

时间:2023-03-29 18:30:22 PHP

场景:最近在搭建PHP服务的时候遇到了一个问题。选用的框架是YII,通过POSTMAN提交数据,提交方式为POST。body主要有以下三个选项:1、form-data2、x-www-form-urlencoded3、raw选择1、form-data时提交可以正常接收POST数据,但是选择raw+JSON时(application/json),POST收到的数据为空,这个问题是什么原因?我们需要从YII实现的原理说起1.通过curl发送json格式的数据,如代码:'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('密码');这种方式获取第一部分通过curljson我们发现post参数不起作用,需要设置yii2请求组件'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.打开yiiwebRequest,找到post()方法:publicfunctionpost($name=null,$defaultValue=null){if($name===null){return$这个->getBodyParams();}返回$this->getBodyParam($name,$defaultValue);}发现值是由$this->getBodyParam($name,$defaultValue)给出然后找到这个方法,代码如下:/***返回请求正文中给出的请求参数。**请求参数是使用[[parsers]]属性中配置的解析器确定的。*如果没有为当前[[contentType]]配置解析器,它会使用PHP函数`mb_parse_str()`*来解析[[rawBody|requestbody]]。*@returnarray请求正文中给出的请求参数。*@throws\yii\base\InvalidConfigException如果注册的解析器没有实现[[RequestParserInterface]]。*@seegetMethod()*@seegetBodyParam()*@seesetBodyParams()*/publicfunctiongetBodyParams(){if($this->_bodyParams===null){if(isset($_POST[$this->方法参数])){$this->_bodyParams=$_POST;取消设置($this->_bodyParams[$this->methodParam]);返回$this->_bodyParams;$rawContentType=$this->getContentType();if(($pos=strpos($rawContentType,';'))!==false){//例如应用程序/json;charset=UTF-8$contentType=substr($rawContentType,0,$pos);}else{$contentType=$rawContentType;}if(isset($this->parsers[$contentType])){$parser=Yii::createObject($this->parsers[$contentType]);if(!($parserinstanceofRequestParserInterface)){thrownewInvalidConfigException("'$contentType'请求解析器无效。它必须实现yii\\web\\RequestParserInterface。");$this->_bodyParams=$parser->parse($this->getRawBody(),$rawContentType);}elseif(isset($this->parsers['*'])){$parser=Yii::createObject($this->parsers['*']);if(!($parserinstanceofRequestParserInterface)){thrownewInvalidConfigException("回退请求解析器无效。它必须实现yii\\web\\RequestParserInterface。");$this->_bodyParams=$parser->parse($this->getRawBody(),$rawContentType);}elseif($this->getMethod()==='POST'){//PHP已经解析了正文所以我们在$_POST中有所有参数$this->_bodyParams=$_POST;}else{$this->_bodyParams=[];mb_parse_str($this->getRawBody(),$this->_bodyParams);}}返回$this->_bodyParams;}打印$rawContentType=$this->getContentType();这个变量,发现他的值是:application/json,然后查看函数getContentType()publicfunctiongetContentType(){if(isset($_SERVER['CONTENT_TYPE'])){返回$_SERVER['CONTENT_TYPE'];}if(isset($_SERVER['HTTP_CONTENT_TYPE'])){//修复错误https://bugs.php.net/bug.php?id=66606return$_SERVER['HTTP_CONTENT_TYPE'];}返回空值;即当我们发送一个json格式的curl请求时,$_SERVER['CONTENT_TYPE']的值为application/json2。回到上面的getBodyParams()函数,它会继续执行下面的代码:if(isset($this->parsers[$contentType])){$parser=Yii::createObject($this->parsers[$内容类型]);if(!($parserinstanceofRequestParserInterface)){thrownewInvalidConfigException("'$contentType'请求解析器无效。它必须实现yii\\web\\RequestParserInterface。");$this->_bodyParams=$parser->parse($this->getRawBody(),$rawContentType);}$parser是在我们下面的请求组件配置中从解析器中获取'yiiwebJsonParser',然后'request'由容器生成=>['class'=>'yii\web\Request','enableCookieValidation'=>false,'parsers'=>['appapplication/json'=>'yii\web\JsonParser',]],所以返回值是$parser->parse($this->getRawBody(),$rawContentType);3、首先,我们检查传入的第一个参数是函数$this->getRawBody(),代码如下:publicfunctiongetRawBody(){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://输入”);这两种方式获取curljson传过来的json数据,yii2用的是第二种然后我们打开yiiwebJsonParser/***解析一个HTTP请求体。*@paramstring$rawBody原始HTTP请求正文。*@paramstring$contentType为请求正文指定的内容类型。*@returnarrayparametersparsedfromtherequestbody*@throwsBadRequestHttpException如果请求体包含无效的json且[[throwException]]为`true`。*/publicfunctionparse($rawBody,$contentType){尝试{$parameters=Json::decode($rawBody,$this->asArray);返回$parameters===null?[]:$参数;}catch(InvalidParamException$e){if($this->throwException){thrownewBadRequestHttpException('请求正文中的无效JSON数据:'.$e->getMessage());}返回[];}}可以看到传过来的json转成数组,然后Yii::request->post('username')可以从返回的数组中获取值汇总:1.在Yii2框架中,使用封装的post()和get()方法,而不是$_POST$_GET等方法,因为两者不相等。2、当使用Yii2作为api时,如果传输的数据是json格式,不要忘记在request组件中添加配置:'request'=>['class'=>'yii\web\Request','解析器'=>['application/json'=>'yii\web\JsonParser',],,,