appserver 中的 /customer/login/account 接口无法识别fetch提交的post数据

问题咨询 · tgy3300 · 于 5年前 发布 · 2068 次阅读

文件位置:@fecshop\app\appserver\modules\Customer\controllers\LoginController.php

该文件里的actionAccount方法下的 

Yii::$app->request->post('password')
和
Yii::$app->request->post('email')

无法获取我fetch提交的post数据

我的请求头信息如下图

我打印 Yii::$app->request->post() 显示为空,求大佬指导,哪错了吗?

共收到 27 条回复
tgy3300#15年前 0 个赞

百度下资料,可以这样接收

$final = file_get_contents('php://input');
$data = json_decode($final, true);

我先暂时这样做,大佬有空看看,这是不是个小问题

Fecmall#25年前 0 个赞

LoginController继承于 https://github.com/fecshop/yii2_fecshop/blob/master/app/appserver/modules/AppserverController.php#L35

$behaviors['contentNegotiator']['formats']['text/html'] = Response::FORMAT_JSON;

通过

Yii::$app->request->post('password')
和
Yii::$app->request->post('email')

是可以获取的

参看之前的我写的分析:http://www.fecshop.com/topic/413

tgy3300#35年前 0 个赞

亲测,真获取不了,我看了我本地的代码

LoginController继承于@fecshop\app\appserver\modules\AppserverController.php文件,该文件也是有

$behaviors['contentNegotiator']['formats']['text/html'] = Response::FORMAT_JSON;

跟了一遍代码, 在\yii\web\Request里的getBodyParams()方法中,

程序走这里
} elseif ($this->getMethod() === 'POST') {
	$this->_bodyParams = $_POST;
}

所以才取不到值

如果程序走这里
if (isset($this->parsers[$contentType])) {
...
}

就不会有问题了

我打印 $this->parsers[$contentType] 为空,打印 $contentType 显示为 application/json

4楼 已删除.
Fecmall#55年前 0 个赞

可以登陆: http://demo.fancyecommerce.com/#/customer/account/login

自己debug一下,找找原因吧

tgy3300#65年前 0 个赞

你看你的请求头和我上面截图中的请求头是否一样,我的表单数据都在request payload里

Fecmall#75年前 0 个赞

@tgy3300 #6楼 demo地址发给你了,你自己不会看吗? 注册个账户自己看。

自己解决

tgy3300#85年前 0 个赞

还真不一样,是 \yii\web\Request.php getBodyParams()方法存在bug

Fecmall#95年前 0 个赞

你二开了代码导致的吧?是你客户端请求的方式不一样导致的,应该和php这边没有关系

自己调试对比吧,解决后这里记录一下如何解决的。

您自己调试吧

successgo#105年前 0 个赞

常规来讲,提交数据有几种形式。

一是地址栏里的 query 参数,也叫 GET。

二是 POST 提交的 FORM 表单数据。但是 POST 请求,还可以提交 Payload 型数据,而这个数据并不是存在 $_POST 中,只能通过 php://input 获取再通过 json_decode。而你的 fetch 刚好就属于这后者,你要么动前端,将 payload 改成 FORM 数据,要么动后端,作一下兼容,将 payload 的数据处理为 $_POST 中去。

tgy3300#115年前 0 个赞

@successgdc #10楼 ,怎么将 payload 的数据处理为 $_POST 中去

Fecmall#125年前 0 个赞

对于php,你的这个数据只能通过 php://input

但是对于Yii2框架,进行了封装,当请求是json的时候,是可以从Yii::$app->request->post()中取出来数据的

我之前有一个对yii2这个方面的分析:http://www.fecshop.com/topic/413

你可以参考debug一下问题原因。

tgy3300#135年前 0 个赞

Yii::$app->request->post()一样不能获取到数据,我debug跟了一遍代码,并在3楼说明了原因,是 \yii\web\Request.php 的 getBodyParams() 方法没有兼顾到我的这种情况,需要改下getBodyParams() 方法,我暂时还不怎么改,先用 php://input

Fecmall#145年前 0 个赞

@tgy3300 #13楼

你的这部分功能,是fecshop默认的功能,还是你二次开发的功能?

Fecmall#155年前 0 个赞

@tgy3300 [#13楼](#comment13)

关于三楼部分的代码,先看:http://www.fecshop.com/topic/413

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;
    }

如果 request组件(component)的配置,设置了parsers

'request' => [
            'class' => 'yii\web\Request',
            'parsers' => [
                 'application/json' => 'yii\web\JsonParser',
            ],
        ],

那么上面的代码中 $this->parsers 就是上面设置的值

[
	'application/json' => 'yii\web\JsonParser',
]

到这里,如果$contentType的值为:application/json,那么就会满足条件,下面的代码就会执行。

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);
            }

isset($this->parsers[$contentType]) 返回为true

Fecmall#165年前 0 个赞

因此,导致你这个问题的原因,要么是 请求类型不是 application/json

要么request组件中没有配置parsers

'request' => [
            'class' => 'yii\web\Request',
            'parsers' => [
                 'application/json' => 'yii\web\JsonParser',
            ],
        ],
tgy3300#175年前 1 个赞

后端接口我是用的fecshop的appserver端,没做过二次开发,前端我是用react开发的一个单页应用,与appserver端接口交互是通过fetch封装的一个js函数,现在的问题的是我前端与接口交互时,fetch提交的数据是放在request payload 的,而不是form data,使用Yii::$app->request->post()时,\yii\web\Request.php 的 getBodyParams() 方法识别不了我的 request payload 数据,所以在getBodyParams() 方法中程序走了下面这一步

} elseif ($this->getMethod() === 'POST') {
	$this->_bodyParams = $_POST;
}
tgy3300#185年前 0 个赞

@Fecshop #15楼 我打印 $this->parsers[$contentType] 为空,打印 $contentType 显示为 application/json

successgo#195年前 0 个赞

你需要配置一个 parser 才行。

Fecmall#205年前 0 个赞

@tgy3300 #18楼 稍等,我看下源码

tgy3300#215年前 0 个赞

@Fecshop [#16楼](#comment16)

'request' => [
            'class' => 'yii\web\Request',
            'parsers' => [
                 'application/json' => 'yii\web\JsonParser',
            ],
        ],

请问下这个是在哪里配置,是不是真的是这个没配置

Fecmall#225年前 0 个赞

我明白你的问题了,fecshop的vue使用的是form提交的数据,而你提交的是json格式数据

因此需要配置,打开文件

@appserver/config/main-local.php

<?php
$config = [
	'components' => [
        'request' => [
            // !!! insert a secret key in the following (if it is empty) - this is required by cookie validation
            'cookieValidationKey' => 'xxxxxxxxxxxxx',
            'parsers' => [
                 'application/json' => 'yii\web\JsonParser',
            ],
        ],
    ],
];

这里添加上试一下是否可以。

23楼 已删除.
Fecmall#245年前 0 个赞

@tgy3300 #23楼 上面回复你了,参看 #22 的内容

tgy3300#255年前 0 个赞

@Fecshop [#24楼](#comment24) 可以了,真是这个问题,我想问下,以后使用vue,通过form提交数据,不用把该配置取消吧?

Fecmall#265年前 0 个赞

@tgy3300 #25楼 无论是vue,还是其他客户端,这些都是无关的, 主要看请求方式,如果ajax的请求是form表单的方式,那么不需要做改动,如果是json的格式,就需要加上这个配置。

successgo#275年前 0 个赞

没事的时候多读读 Yii 框架的源码。

tgy3300#285年前 0 个赞

@Fecshop #26楼 感谢大佬,明白了,

tgy3300#295年前 0 个赞

@successgdc [#27楼](#comment27) 嗯,正在学习中,fecshop是个学习yii的好案例源码

添加回复 (需要登录)
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册
Your Site Analytics