CakePHP中的Ajax错误处理

pau*_*ith 8 php ajax error-handling cakephp

我想做一些与非常类似的事情,但是在CakePHP世界中,我们需要AJAX请求.目前我这样做:

$this->autoRender = false;
$this->response->statusCode(500);
Run Code Online (Sandbox Code Playgroud)

它基于.但是,此解决方案不允许我包含像Rails示例中的自定义消息,这样,在我的客户端错误处理程序中,我可以显示500错误响应中包含的消息.

我如何在CakePHP中实现相同的功能,如Ruby on Rails示例?

thr*_*eve 7

如上所述,Exceptions是在CakePHP中返回AJAX请求错误的方法.这是我的解决方案,可以更好地控制错误的样子.此外,如上所述,我使用自定义的异常渲染器,但不是自定义异常.默认的错误响应是这样的JSON对象:

{"name":"An Internal Error Has Occurred", "url": "\/users\/login.json"}
Run Code Online (Sandbox Code Playgroud)

几乎喜欢默认渲染器处理AJAX错误的方式; 我只是想稍微调整一下:

<?php
// File: /app/Lib/Error/CustomExceptionRenderer.php
App::uses('ExceptionRenderer', 'Error');
class CustomExceptionRenderer extends ExceptionRenderer {

    // override
    public function error400($error) {
        $this->_prepareView($error, 'Not Found');
        $this->controller->response->statusCode($error->getCode());

        $this->_outputMessage('error400');
    }

    // override
    public function error500($error) {
        $this->_prepareView($error, 'An Internal Error Has Ocurred.');
        $code = ($error->getCode() > 500 && $error->getCode() < 506) ? $error->getCode() : 500;
        $this->controller->response->statusCode($code);

        $this->_outputMessage('error500');
    }

    private function _prepareView($error, $genericMessage) {
        $message = $error->getMessage();
        if(!Configure::read('debug') && !Configure::read('detailed_exceptions')) {
            $message = __d('cake', $genericMessage);
        }
        $url = $this->controller->request->here();
        $renderVars = array(
            'name' => h($message),
            'url' => h($url),
            );
        if(isset($this->controller->viewVars['csrf_token'])) {
            $renderVars['csrf_token'] = $this->controller->viewVars['csrf_token'];
        }
        $renderVars['_serialize'] = array_keys($renderVars);
        $this->controller->set($renderVars);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,在bootstrap.php中:

Configure::write('Exception.renderer', 'CustomExceptionRenderer');
Run Code Online (Sandbox Code Playgroud)

所以这是它的工作原理:

  • 假设我想在我的错误响应中返回一个新的CSRF令牌,这样如果我的现有令牌在抛出异常之前已经过期,那么下次我尝试请求时我就不会被黑洞化了.有关CSRF保护的更多信息,请查看安全组件文档.
  • 在app/Lib/Error中创建一个新类.您可以扩展默认渲染器.因为我只是想改变一些小东西,并保持简单的例子,我正在扩展它.
  • 覆盖默认渲染器用于创建将返回的JSON对象的方法.这是通过请求处理程序组件完成的,并符合最佳实践.实际上,默认渲染器也会做同样的事情.
  • 保持干燥的新私人方法.
  • 我在生产中没有获得自定义错误消息的问题的解决方案是添加可选配置密钥.默认情况下,此类将显示生产中的通用消息,但如果您将调试设置为0,并且您需要特定的错误消息:Configure::write('detailed_exceptions', 1);
  • 将新令牌添加到响应(如果存在).在我的例子中,我已经Controller::set在AppController的beforeFilter方法中调用了新标记,因此可以使用它$this->controller->viewVars.可能有很多其他方法可以实现这一目标.

现在您的回复如下:

{
    "name":"The request has been black-holed",
    "url":"\/users\/login.json",
    "csrf_token":"1279f22f9148b6ff30467abaa06d83491c38e940"
}
Run Code Online (Sandbox Code Playgroud)

可以将任何类型的任何其他数据添加到传递给Controller::set相同结果的数组中.


lor*_*key 0

您可以按照食谱中的说明使用 CakeExceptions:http://book.cakephp.org/2.0/en/development/exceptions.html 如果您想使用自定义消息,我发现除了debug = 1在生产模式中使用之外没有其他方法: (

这是我使用内置方法的方法:

在你的控制器中:

if($this->request->is('ajax')){
    Configure::write('debug', 1);
}

if(!$allowed) {
    throw new InternalErrorException('Keep your fingers away from me!'); // 500 error
}
Run Code Online (Sandbox Code Playgroud)

更改错误模板以在 AJAX 调用中使用时只输出错误/app/View/Errors/error500.ctp:

<?php
if($this->request->is('ajax')):
    // Output for AJAX calls
    echo $name;

else:
    //Standard CakePHP output ?>
    <h2><?php echo $name; ?></h2>
    <p class="error">
        <strong><?php echo __d('cake', 'Error'); ?>: </strong>
        <?php echo __d('cake', 'An Internal Error Has Occurred.'); ?>
    </p>
    <?php
    if (Configure::read('debug') > 0 ):
        echo $this->element('exception_stack_trace');
    endif;

endif; ?>
Run Code Online (Sandbox Code Playgroud)

然后您可以在 AJAX 中解析返回的文本。这是我使用的 jQuery 部分:

//...
error: function (request) {
    yourErrorShowingFunction(_this, request.responseText);
}
//...
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助 :)

如果有人知道如何在生产模式下使用自定义错误(而不覆盖调试模式),我会非常高兴!