CakePHP 3.5 400 错误请求

Posted

技术标签:

【中文标题】CakePHP 3.5 400 错误请求【英文标题】:CakePHP 3.5 400 Bad Request 【发布时间】:2018-07-07 16:23:56 【问题描述】:

我正在开发一个带有基于 webonyx 的 GraphQL-php 包的 GraphQL 端点的 CakePHP。问题是 post 和 multipart 方法返回 400 错误请求。我最初认为这是由于预检请求得到处理而后续被忽略或一个简单的 cors 问题,但在对代码进行了广泛的调试和修改之后。我已经确定这些设置正确。我使用this 插件来管理预检请求。默认配置允许所有来源并且问题仍然存在。

处理请求的动作方法如下所示。

    public function index()
        $this->autoRender = false;

        $data = $this->request->input('json_decode');

        if(!$data) 
            $data = $this->request->getParam('?');
        

        if(!$data) $data = [];
        $data += ['query' => null, 'variables' => null];
        $result = $this->GraphQL->query($data);

        $this->response = $this->response
        ->withHeader('Access-Control-Allow-Origin', '*')
        ->withHeader('Access-Control-Allow-Methods', ['GET', 'POST', 'OPTIONS'])
        ->withHeader('Access-Control-Allow-Credentials', 'true')
        ->withHeader('Access-Control-Max-Age','8600')
        ->withType('application/json')
        ->withStringBody(json_encode($result));
        return $this->response;
    

但这不是问题的原因。 POST 和 MULTIPART 在返回错误之前甚至不会进入此函数。我已经用 GraphiQL Fen 测试了端点。

这是错误日志中生成的堆栈跟踪。

2018-01-29 22:28:35 Warning: DebugKit not enabled. You need to either install pdo_sqlite, or define the "debug_kit" connection name.
2018-01-29 22:28:36 Warning: DebugKit not enabled. You need to either install pdo_sqlite, or define the "debug_kit" connection name.
2018-01-29 22:28:47 Warning: DebugKit not enabled. You need to either install pdo_sqlite, or define the "debug_kit" connection name.
2018-01-29 22:28:48 Error: [Cake\Controller\Exception\AuthSecurityException] '_Token' was not found in request data.
Request URL: /api
Stack Trace:
#0 /path/radioactive-cake/app/vendor/cakephp/cakephp/src/Controller/Component/SecurityComponent.php(316): Cake\Controller\Component\SecurityComponent->_validToken(Object(App\Controller\ApiController))
#1 /path/radioactive-cake/app/vendor/cakephp/cakephp/src/Controller/Component/SecurityComponent.php(121): Cake\Controller\Component\SecurityComponent->_validatePost(Object(App\Controller\ApiController))
#2 /path/radioactive-cake/app/vendor/cakephp/cakephp/src/Event/EventManager.php(416): Cake\Controller\Component\SecurityComponent->startup(Object(Cake\Event\Event))
#3 /path/radioactive-cake/app/vendor/cakephp/cakephp/src/Event/EventManager.php(393): Cake\Event\EventManager->_callListener(Array, Object(Cake\Event\Event))
#4 /path/radioactive-cake/app/vendor/cakephp/cakephp/src/Event/EventDispatcherTrait.php(110): Cake\Event\EventManager->dispatch(Object(Cake\Event\Event))
#5 /path/radioactive-cake/app/vendor/cakephp/cakephp/src/Controller/Controller.php(506): Cake\Controller\Controller->dispatchEvent('Controller.star...')
#6 /path/radioactive-cake/app/vendor/cakephp/cakephp/src/Http/ActionDispatcher.php(114): Cake\Controller\Controller->startupProcess()
#7 /path/radioactive-cake/app/vendor/cakephp/cakephp/src/Http/ActionDispatcher.php(93): Cake\Http\ActionDispatcher->_invoke(Object(App\Controller\ApiController))
#8 /path/radioactive-cake/app/vendor/cakephp/cakephp/src/Http/BaseApplication.php(108): Cake\Http\ActionDispatcher->dispatch(Object(Cake\Http\ServerRequest), Object(Cake\Http\Response))
#9 /path/radioactive-cake/app/vendor/cakephp/cakephp/src/Http/Runner.php(65): Cake\Http\BaseApplication->__invoke(Object(Cake\Http\ServerRequest), Object(Cake\Http\Response), Object(Cake\Http\Runner))
#10 /path/radioactive-cake/app/vendor/ozee31/cakephp-cors/src/Routing/Middleware/CorsMiddleware.php(31): Cake\Http\Runner->__invoke(Object(Cake\Http\ServerRequest), Object(Cake\Http\Response))
#11 /path/radioactive-cake/app/vendor/cakephp/cakephp/src/Http/Runner.php(65): Cors\Routing\Middleware\CorsMiddleware->__invoke(Object(Cake\Http\ServerRequest), Object(Cake\Http\Response), Object(Cake\Http\Runner))
#12 /path/radioactive-cake/app/vendor/cakephp/cakephp/src/Routing/Middleware/RoutingMiddleware.php(104): Cake\Http\Runner->__invoke(Object(Cake\Http\ServerRequest), Object(Cake\Http\Response))
#13 /path/radioactive-cake/app/vendor/cakephp/cakephp/src/Http/Runner.php(65): Cake\Routing\Middleware\RoutingMiddleware->__invoke(Object(Cake\Http\ServerRequest), Object(Cake\Http\Response), Object(Cake\Http\Runner))
#14 /path/radioactive-cake/app/vendor/cakephp/cakephp/src/Routing/Middleware/AssetMiddleware.php(88): Cake\Http\Runner->__invoke(Object(Cake\Http\ServerRequest), Object(Cake\Http\Response))
#15 /path/radioactive-cake/app/vendor/cakephp/cakephp/src/Http/Runner.php(65): Cake\Routing\Middleware\AssetMiddleware->__invoke(Object(Cake\Http\ServerRequest), Object(Cake\Http\Response), Object(Cake\Http\Runner))
#16 /path/radioactive-cake/app/vendor/cakephp/cakephp/src/Error/Middleware/ErrorHandlerMiddleware.php(95): Cake\Http\Runner->__invoke(Object(Cake\Http\ServerRequest), Object(Cake\Http\Response))
#17 /path/radioactive-cake/app/vendor/cakephp/cakephp/src/Http/Runner.php(65): Cake\Error\Middleware\ErrorHandlerMiddleware->__invoke(Object(Cake\Http\ServerRequest), Object(Cake\Http\Response), Object(Cake\Http\Runner))
#18 /path/radioactive-cake/app/vendor/cakephp/cakephp/src/Http/Runner.php(51): Cake\Http\Runner->__invoke(Object(Cake\Http\ServerRequest), Object(Cake\Http\Response))
#19 /path/radioactive-cake/app/vendor/cakephp/cakephp/src/Http/Server.php(81): Cake\Http\Runner->run(Object(Cake\Http\MiddlewareQueue), Object(Cake\Http\ServerRequest), Object(Cake\Http\Response))
#20 /path/radioactive-cake/app/webroot/index.php(40): Cake\Http\Server->run()
#21 main 

它还指出请求数据中缺少 _Token,但我在 beforeFilter 函数中禁用了 CSRF,如下所示。

public function beforeFilter(Event $event)

    parent::beforeFilter($event);
    $this->Auth->allow('index');
    $this->eventManager()->off($this->Csrf);

附带说明一下,使用前三行中提到的 debug_kit 连接会提供更详细的输出吗?

【问题讨论】:

如果错误是在 CakePHP 端触发的,那么日志中应该有相应的错误消息和堆栈跟踪(请参阅logs 文件夹),请始终将这些包含在您的问题中。如果没有日志条目,那么错误可能发生在服务器级别,或者至少在 CakePHP 请求周期之外。 谢谢我完全忽略了应用程序日志文件,我检查了我的服务器日志并且在请求期间没有抛出任何错误。 我实际上将它修改为在回答这个问题***.com/questions/37360734/… 时完成的方式,我不再收到错误。如果没有你的帮助,我永远不会解决这个问题。非常感谢,你已经连续两天成为我的英雄了。 不客气。 DebugKit 很可能不会为您提供更多详细信息,该消息只是插件在引导时记录的默认消息,以防它被启用,但无法存储生成的调试数据。如果它可以存储数据,那么您将能够通过插件 GUI 检查先前请求的调试历史记录(即响应 html 文档的请求)。 我明白了。好吧,我的 graphql 组件现在可以完美运行,但我还没有实现突变,查看请求内容的能力将为我省去很多麻烦。现在,我只是在调试时使用自定义组件将json_encode($this->request) 写入日志文件。 【参考方案1】:

CSRF 被不当禁用。我的 beforeFilter 应该是这样的。

public function beforeFilter(Event $event)

    parent::beforeFilter($event);
    $this->Auth->allow('index');
    $actions = [
        'index',
    ];

    if (in_array($this->request->params['action'], $actions)) 
        // for csrf
        $this->eventManager()->off($this->Csrf);

        // this is a must have
        $this->Security->config('unlockedActions', $actions);
    

【讨论】:

以上是关于CakePHP 3.5 400 错误请求的主要内容,如果未能解决你的问题,请参考以下文章

在AWS S3上存储CakePHP库以用于多个应用程序

CakePHP 3.5复选框数组

CakePHP 3.5:通过Composer安装后无法访问插件类

Cakephp 3.5 多次保存相同的记录

如何在 Cakephp 3.5 中设置和获取 Cookie

Cakephp 3.4 AJAX 请求抛出 403 禁止错误