2012-07-20 13 views
8

Chcę zrobić coś bardzo podobnego do this, ale w świecie CakePHP dla żądań AJAX. W tej chwili robię to:Obsługa błędów Ajax w CakePHP

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

Jest on oparty off this. Jednak to rozwiązanie nie pozwala mi na dołączenie niestandardowego komunikatu, jak w przykładzie Rails, więc w ten sposób po stronie obsługi błędów po stronie klienta mogę wyświetlić komunikat zawarty w odpowiedzi na błąd 500.

Jak zaimplementować tę samą funkcjonalność w CakePHP, jak przykład Ruby on Rails?

Odpowiedz

0

Można użyć CakeExceptions jak wyjaśniono w Cookbook: http://book.cakephp.org/2.0/en/development/exceptions.htmlALE, jeśli chcesz korzystać z niestandardowych komunikatów nie znalazłem inny sposób niż za pomocą debug = 1 w trybie produkcyjnym :(

Oto moje podejście z wbudowanym metody:

W kontrolerze:

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

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

Zmień szablon błędu wyjściowego nic ale błąd przy stosowaniu w AJAX wywołuje w /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; ?> 

Następnie można analizować zwrócony tekst w AJAX. Oto Części jQuery używam:

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

Nadzieja to pomaga :)

Jeśli ktoś ma pomysł, jak korzystać z błędów niestandardowych w trybie produkcyjnym (bez nadpisywania tryb debugowania) Byłbym bardzo szczęśliwy!

+0

Mimo że nie była to odpowiedź, na którą liczyłem, ponieważ wywoła ona tryb debugowania, oznaczy to jako poprawną, ponieważ nikt inny nie wydaje się mieć żadnych pomysłów na ten temat. Dzięki za wysiłek! –

2

Mam również borykałem się z niestandardowymi wyjątkami i kodami błędów przy korzystaniu z zapytań ajax (jquery mobile w moim przypadku). Oto rozwiązanie, które wymyśliłem, bez konieczności nadpisywania trybu debugowania. Zgłasza błędy niestandardowe w trybie programowania, a także opcjonalnie w trybie produkcyjnym. Mam nadzieję, że ktoś pomaga:

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

można pominąć Configure::read('debug') > 0 jeśli chcesz wyświetlić wyjątek w trybie debugowania. Widok errorjson.ctp znajduje się w "Error/errorjson.CTP ":

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

W tym przypadku moja Wyjątkiem jest nazywany

TestException

i jest zdefiniowany następująco:

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

Gdzie mam niestandardowy kod błędu 2, $code = 2, dla mojej odpowiedzi jsona. Odpowiedź ajax rzuci błąd 500 z następującymi danymi json:

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

Oczywiście, trzeba także wyrzucić wyjątek od kontrolera:

throw new TestException(); 

i obejmują mechanizm renderujący wyjątku http://book.cakephp.org/2.0/en/development/exceptions.html#using-a-custom-renderer-with-exception-renderer-to-handle-application-exceptions

Może to być nieco poza zakresem, ale aby obsłużyć odpowiedź błędu ajax w JQuery używam:

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

Działa bardzo dobrze. Dzięki. – MotsManish

7

Jak wspomniano powyżej, wyjątki są sposobem na zwrócenie błędu w żądaniu AJAX w CakePHP. Oto moje rozwiązanie pozwalające uzyskać lepszą kontrolę nad tym, jak wygląda błąd. Ponadto, tak jak powyżej, używam niestandardowego renderera wyjątków, ale nie wyjątku niestandardowego. Odpowiedź domyślna błąd jest obiekt JSON tak:

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

I prawie jak sposób, że domyślny renderer obsługuje błędy AJAX; Chcę tylko, aby dostosować go trochę:

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

Następnie w bootstrap.php:

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

Więc oto jak to działa:

  • że chcę wrócić nowa Token CSRF w mojej odpowiedzi o błędzie, więc jeśli mój istniejący token wygasł przed wyrzuceniem wyjątku, nie dostaję blackholingu przy następnej próbie wykonania żądania. Sprawdź numer Security Component documentation, aby uzyskać więcej informacji na temat ochrony CSRF.
  • Utwórz nową klasę w aplikacji/Lib/Błąd. Możesz rozszerzyć domyślny mechanizm renderujący lub nie. Ponieważ chcę tylko zmienić kilka drobiazgów i zachować prosty przykład, przedłużam to.
  • Zastępuje metody używane przez domyślny renderer do utworzenia obiektu JSON, który zostanie zwrócony. Odbywa się to za pośrednictwem Request Handler Component i jest zgodne z najlepszymi praktykami. Rzeczywiście, domyślny renderer robi to samo.
  • Nowa prywatna metoda utrzymywania porządku w stanie SUCHYM.
  • Moim rozwiązaniem problemu polegającego na nieotrzymaniu niestandardowych komunikatów o błędach w produkcji jest dodanie opcjonalnego klucza konfiguracyjnego. Domyślnie ta klasa będzie wyświetlać generyczne komunikaty w procesie produkcyjnym, ale jeśli masz ustawione debugowanie na 0 i chcesz, aby określone komunikaty o błędach: Configure::write('detailed_exceptions', 1);
  • Dodaj nowy token do odpowiedzi, jeśli istnieje.W moim przypadku już nazywane Controller::set na nowym tokenie w metody beforeFilter AppController, więc jest dostępny w $this->controller->viewVars. Prawdopodobnie istnieje dziesiątki innych sposobów na osiągnięcie tego.

Teraz twoja reakcja wygląda następująco:

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

Wszelkie dodatkowe dane dowolnego typu mogą być dodawane do tablicy przekazany do Controller::set do tego samego rezultatu.

+0

to bardzo mi pomaga. –