2012-07-20 13 views
8

Tôi muốn làm điều gì đó rất giống với this nhưng trong thế giới CakePHP cho các yêu cầu AJAX. Hiện tại tôi đang thực hiện việc này:Xử lý lỗi Ajax trong CakePHP

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

Nó dựa trên this. Tuy nhiên giải pháp này không cho phép tôi bao gồm một thông báo tùy chỉnh như trong ví dụ Rails, do đó, theo cách đó, trong trình xử lý lỗi phía khách hàng của tôi, tôi có thể hiển thị thông báo được bao gồm trong phản hồi lỗi 500.

Làm cách nào để triển khai cùng chức năng trong CakePHP như ví dụ về Ruby on Rails?

Trả lời

0

Bạn có thể sử dụng CakeExceptions như được giải thích trong Cookbook: http://book.cakephp.org/2.0/en/development/exceptions.htmlNHƯNG nếu bạn muốn sử dụng tin nhắn tùy chỉnh của bạn tôi thấy không có cách nào khác hơn là sử dụng debug = 1 trong chế độ sản xuất của bạn :(

Dưới đây là cách tiếp cận của tôi với xây dựng trong phương pháp:

Trong điều khiển của bạn:

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

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

Thay đổi lỗi mẫu không có gì đầu ra nhưng báo lỗi khi sử dụng trong các cuộc gọi AJAX trong /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; ?> 

Sau đó bạn có thể phân tích các văn bản trả lại trong AJAX của bạn. Dưới đây là những phần jQuery tôi sử dụng:

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

Hope this helps :)

Nếu ai có ý tưởng làm thế nào để sử dụng các lỗi tùy chỉnh trong phương thức sản xuất (không ghi đè lên các chế độ gỡ lỗi) tôi sẽ rất vui!

+0

Mặc dù đây không phải là câu trả lời tôi đã hy vọng vì nó được phát hành ở chế độ gỡ lỗi, tôi sẽ đánh dấu nó là chính xác vì không ai khác có bất kỳ ý tưởng nào về điều này. Cảm ơn cho những nỗ lực! –

2

Tôi cũng đã gặp khó khăn với các ngoại lệ tùy chỉnh và mã lỗi khi sử dụng yêu cầu ajax (jquery di động trong trường hợp của tôi). Đây là giải pháp mà tôi đưa ra, mà không liên quan đến việc ghi đè chế độ gỡ lỗi. Nó ném lỗi tùy chỉnh trong chế độ phát triển, và cũng tùy chọn trong chế độ sản xuất. Tôi hy vọng nó sẽ giúp ai đó:

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

Bạn có thể bỏ qua Configure::read('debug') > 0 nếu bạn muốn hiển thị các ngoại lệ trong chế độ gỡ lỗi. Chế độ xem errorjson.ctp được đặt trong 'Lỗi/lỗi báo lỗi.ctp ':

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

Trong trường hợp này ngoại lệ của tôi được gọi là

TestException

và được định nghĩa như sau:

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

Nơi tôi có một mã lỗi tùy chỉnh 2, $code = 2, để trả lời json của tôi. Các phản ứng ajax sẽ đúc một lỗi 500 với dữ liệu json sau:

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

Rõ ràng, bạn cũng cần phải ném ngoại lệ từ điều khiển của bạn:

throw new TestException(); 

và bao gồm các renderer ngoại lệ http://book.cakephp.org/2.0/en/development/exceptions.html#using-a-custom-renderer-with-exception-renderer-to-handle-application-exceptions

Điều này có thể hơi lệch phạm vi, nhưng để xử lý phản hồi lỗi ajax trong JQuery tôi sử dụng:

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

Hoạt động rất tốt. Cảm ơn. – MotsManish

7

Như đã đề cập ở trên, Ngoại lệ là cách trả về lỗi trên yêu cầu AJAX trong CakePHP. Đây là giải pháp của tôi để đạt được quyền kiểm soát tốt hơn về những gì lỗi trông như thế nào. Ngoài ra, như trên, tôi đang sử dụng Trình kết xuất ngoại lệ tùy chỉnh, nhưng không phải là ngoại lệ tùy chỉnh. Câu trả lời báo lỗi mặc định là một đối tượng JSON như thế này:

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

tôi gần như cách mà các renderer mặc định xử lý các lỗi AJAX; Tôi chỉ muốn tinh chỉnh nó một chút:

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

Sau đó, trong bootstrap.php:

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

Vì vậy, đây là cách hoạt động:

  • Nói rằng tôi muốn trở lại một mới Mã thông báo CSRF trong phản hồi lỗi của tôi, để nếu mã thông báo hiện tại của tôi đã hết hạn trước khi ngoại lệ được ném, tôi không bị bôi đen vào lần tiếp theo tôi thử yêu cầu. Hãy xem Security Component documentation để biết thêm về bảo vệ CSRF.
  • Tạo một lớp mới trong ứng dụng/Lib/Lỗi. Bạn có thể mở rộng trình kết xuất đồ họa mặc định hoặc không. Vì tôi chỉ muốn thay đổi một vài điều nhỏ, và để giữ cho ví dụ đơn giản, tôi đang mở rộng nó.
  • Ghi đè các phương thức mà trình kết xuất đồ họa mặc định sử dụng để tạo đối tượng JSON sẽ được trả lại. Điều này được thực hiện thông qua Request Handler Component và tuân thủ các phương pháp hay nhất. Thật vậy, trình kết xuất mặc định thực hiện điều tương tự.
  • Phương pháp riêng tư mới để giữ mọi thứ KHÔ.
  • Giải pháp của tôi đối với vấn đề không nhận được thông báo lỗi tùy chỉnh trong sản xuất là thêm khóa cấu hình tùy chọn. Theo mặc định, lớp này sẽ hiển thị các thông báo chung trong quá trình sản xuất, nhưng nếu bạn đã gỡ lỗi được đặt thành 0 và bạn muốn thông báo lỗi cụ thể: Configure::write('detailed_exceptions', 1);
  • Thêm mã thông báo mới vào phản hồi nếu nó tồn tại.Trong trường hợp của tôi, tôi đã gọi số Controller::set trên mã thông báo mới trong phương thức trước của AppController, vì vậy nó có sẵn trong $this->controller->viewVars. Có thể có hàng chục cách khác để hoàn thành việc này.

Bây giờ phản ứng của bạn trông như thế này:

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

Mọi dữ liệu bổ sung, của bất kỳ loại có thể được bổ sung vào mảng truyền cho Controller::set cho kết quả tương tự.

+0

điều này thực sự giúp tôi rất nhiều. –