2012-07-20 109 views
8

我想要做一些非常类似于this的事情,但在CakePHP世界中用于AJAX请求。目前,我这样做:CakePHP中的Ajax错误处理

$this->autoRender = false; 
$this->response->statusCode(500); 

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

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

回答

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 
} 

变化在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; ?> 

然后,您可以分析您的AJAX返回的文本。这里是jQuery的部分我用:

//... 
error: function (request) { 
    yourErrorShowingFunction(_this, request.responseText); 
} 
//... 

希望这有助于:)

如果任何人有一个想法如何在生产中使用模式自定义错误(但不覆盖调试模式)我会很高兴!

+0

即使这并不是我希望的答案,因为它调用了调试模式,我将其标记为正确,因为没有人似乎对此有任何想法。感谢您的努力! – 2012-08-22 17:15:12

2

当我使用ajax请求(我的情况下是jquery mobile)时,我也遇到了自定义异常和错误代码。这是我提出的解决方案,不涉及覆盖调试模式。它会在开发模式中引发自定义错误,并且还可以选择在生产模式下。我希望它可以帮助别人:

AppExceptionRenderer.php:

<?php 
App::uses('ExceptionRenderer', 'Error'); 

class AppExceptionRenderer extends ExceptionRenderer 
{ 
    public function test($error) 
    { 
     $this->_sendAjaxError($error); 
    } 

    private function _sendAjaxError($error) 
    { 
     //only allow ajax requests and only send response if debug is on 
     if ($this->controller->request->is('ajax') && Configure::read('debug') > 0) 
     { 
      $this->controller->response->statusCode(500); 
      $response['errorCode'] = $error->getCode(); 
      $response['errorMessage'] = $error->getMessage(); 
      $this->controller->set(compact('response')); 
      $this->controller->layout = false; 
      $this->_outputMessage('errorjson'); 
     } 
    } 
} 

你可以离开了Configure::read('debug') > 0,如果你想显示在调试模式下除外。查看errorjson.ctp位于'Error/errorjson。CTP“:

<?php 
echo json_encode($response); 
?> 

在这种情况下我的异常被称为

TestException

,并定义如下:

<?php 
class TestException extends CakeException { 
    protected $_messageTemplate = 'Seems that %s is missing.'; 

    public function __construct($message = null, $code = 2) { 
     if (empty($message)) { 
        $message = 'My custom exception.'; 
      } 
      parent::__construct($message, $code); 
    } 
} 

如果我有一个自定义错误代码2,$code = 2,为我的JSON响应。 Ajax响应将铸就一个错误500以下JSON数据:

{"errorCode":"2","errorMessage":"My custom exception."} 

很明显,你还需要从您的控制器抛出异常:

throw new TestException(); 

,包括异常渲染http://book.cakephp.org/2.0/en/development/exceptions.html#using-a-custom-renderer-with-exception-renderer-to-handle-application-exceptions

这可能有点超出范围,但要处理我使用的JQuery中的ajax错误响应:

$(document).ajaxError(function (event, jqXHR, ajaxSettings, thrownError) { 
    //deal with my json error 
}); 
+0

工作得很好。谢谢。 – MotsManish 2015-05-15 07:29:53

7

如上所述,异常是在CakePHP中的AJAX请求上返回错误的方式。这是我的解决方案,用于更好地控制错误的样子。另外,如上所述,我使用自定义的Exception Renderer,但不是自定义的异常。默认的错误响应是一个JSON对象,像这样:

{"name":"An Internal Error Has Occurred", "url": "\/users\/login.json"} 

几乎这样的默认渲染处理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); 
    } 
} 

然后,在bootstrap.php中:

Configure::write('Exception.renderer', 'CustomExceptionRenderer'); 

因此,这里是如何工作的:

  • 说我想返回一个新的CSRF令牌在我的错误响应中,所以如果我现有的令牌在抛出异常之前已经过期,那么下次尝试请求时我不会被盗取。查看Security Component documentation了解CSRF保护的更多信息。
  • 在app/Lib/Error中创建一个新类。您可以扩展默认渲染器,或不扩展。因为我只想改变一些小的东西,并保持简单的例子,我正在扩展它。
  • 覆盖默认渲染器用于创建将返回的JSON对象的方法。这通过Request Handler Component完成,并符合最佳实践。事实上,默认的渲染器会做同样的事情。
  • 新的私人方法让东西干爽。
  • 我解决在生产中未能获取自定义错误消息的问题是添加一个可选的配置密钥。默认情况下,此类将显示生产中的通用消息,但是如果您将调试设置为0,并且需要特定的错误消息:Configure::write('detailed_exceptions', 1);
  • 如果响应存在,则添加新令牌。在我的情况下,我已经在AppController的beforeFilter方法的新标记上调用Controller::set,因此它在$this->controller->viewVars中可用。有可能有其他几十种方法来完成这一点。

现在你的反应是这样的:

{ 
    "name":"The request has been black-holed", 
    "url":"\/users\/login.json", 
    "csrf_token":"1279f22f9148b6ff30467abaa06d83491c38e940" 
} 

任何额外的数据,任何类型都可以加入到传递给Controller::set了相同的结果阵列。

+0

这真的帮了我很多。 – 2016-11-03 09:12:34