【问题标题】:Yii: Catching all exceptions for a specific controllerYii:捕获特定控制器的所有异常
【发布时间】:2012-06-23 01:22:31
【问题描述】:

我正在开发一个包含 REST API 组件的项目。我有一个专门处理所有 REST API 调用的控制器。

是否有任何方法可以捕获该特定控制器的所有异常,以便我可以针对这些异常采取与应用程序的其余控制器不同的操作?

IE:我想使用包含异常消息的 XML/JSON 格式的 API 响应来响应,而不是默认的系统视图/堆栈跟踪(这在 API 上下文中并不是很有用)。宁愿不必将控制器中的每个方法调用都包装在自己的 try/catch 中。

提前感谢您的任何建议。

【问题讨论】:

    标签: yii


    【解决方案1】:

    你可以通过注册 onErroronException 事件监听器来完全绕过 Yii 的默认错误显示机制。

    例子:

    class ApiController extends CController
    {
      public function init()
      {
        parent::init();
    
        Yii::app()->attachEventHandler('onError',array($this,'handleError'));
        Yii::app()->attachEventHandler('onException',array($this,'handleError'));
      }
    
      public function handleError(CEvent $event)
      {        
        if ($event instanceof CExceptionEvent)
        {
          // handle exception
          // ...
        }
        elseif($event instanceof CErrorEvent)
        {
          // handle error
          // ...
        }
    
        $event->handled = TRUE;
      }
    
      // ...
    }
    

    【讨论】:

    • 谢谢,我已经尝试了各种方法,但您的解决方案是迄今为止覆盖 API 控制器等错误/异常处理程序的最佳方法。
    • 如果有一个ErrorHandler 可能会在您的控制器有机会之前捕获异常,请小心。我被我的代码库中的一些自定义异常处理程序所困扰,这些处理程序将优先。在你的代码库中寻找 `addExceptionHandler` 调用的出现。我放弃了这种方法,并在包罗万象的方法之前附加了一个新的错误处理程序,我不得不搜索并构建一个实现IExceptionHandler 的处理程序。可能必须改变方法以从相关控制器中抛出更具体的异常。
    【解决方案2】:

    我无法在控制器中附加事件,我通过重新定义 CWebApplication 类来做到这一点:

    class WebApplication extends CWebApplication
    {
    protected function init()
    {
        parent::init();
    
        Yii::app()->attachEventHandler('onError',array($this, 'handleApiError'));
        Yii::app()->attachEventHandler('onException',array($this, 'handleApiError'));
    }
    
    /**
     * Error handler
     * @param CEvent $event
     */
    public function handleApiError(CEvent $event)
    {
        $statusCode = 500;
    
        if($event instanceof CExceptionEvent)
        {
            $statusCode = $event->exception->statusCode;
            $body = array(
                'code' => $event->exception->getCode(),
                'message' => $event->exception->getMessage(),
                'file' => YII_DEBUG ? $event->exception->getFile() : '*',
                'line' => YII_DEBUG ? $event->exception->getLine() : '*'
            );
        }
        else
        {
            $body = array(
                'code' => $event->code,
                'message' => $event->message,
                'file' => YII_DEBUG ? $event->file : '*',
                'line' => YII_DEBUG ? $event->line : '*'
            );
        }
    
        $event->handled = true;
    
        ApiHelper::instance()->sendResponse($statusCode, $body);
    }
    }
    

    在 index.php 中:

    require_once(dirname(__FILE__) . '/protected/components/WebApplication.php');
    Yii::createApplication('WebApplication', $config)->run();
    

    【讨论】:

      【解决方案3】:

      您可以为每个控制器编写自己的 actionError() 函数。有几种方法可以做到这一点here

      【讨论】:

        【解决方案4】:

        我正在为 API 使用以下 Base 控制器,请注意,它不是无状态 API,但它也可以提供服务。

        类 BaseJSONController 扩展 CController{

                public $data = array();
        
                public $layout;
        
                public function filters()
                {
                        return array('mainLoop');
                }
        
                /**
                 * it all starts here
                 * @param unknown_type $filterChain
                 */
                public function filterMainLoop($filterChain){
                        $this->data['Success'] = true;
                        $this->data['ReturnMessage'] = "";
                        $this->data['ReturnCode'] = 0;
                        try{
                                $filterChain->run();
        
                        }catch (Exception $e){
                                $this->data['Success'] = false;
                                $this->data['ReturnMessage'] = $e->getMessage();
                                $this->data['ReturnCode'] = $e->getCode(); 
                        }
        
                        echo json_encode($this->data);
                }
        }
        

        您还可以捕获 dbException 并通过电子邮件发送它们,因为它们有些关键,并且可以显示代码/数据库设计中的潜在问题。

        【讨论】:

          【解决方案5】:

          将此添加到您的控制器:

          Yii::app()->setComponents(array(
              'errorHandler'=>array(
                  'errorAction'=>'error/error'
              )
          ));
          

          【讨论】:

            猜你喜欢
            • 2011-04-11
            • 2014-05-21
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-07-16
            • 1970-01-01
            相关资源
            最近更新 更多