9

私はこれと非常に似たようなことをしたいのですが、AJAX リクエストの CakePHP の世界で。現時点で私はこれをやっています:

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

これに基づいています。ただし、このソリューションでは、Rails の例のようにカスタム メッセージを含めることはできません。そのため、クライアント側のエラー ハンドラで、500 エラー レスポンスに含まれるメッセージを表示できます。

Ruby on Rails の例のように、CakePHP で同じ機能を実装するにはどうすればよいですか?

4

3 に答える 3

7

上記のように、例外は CakePHP の AJAX リクエストでエラーを返す方法です。エラーがどのように見えるかをより細かく制御するための私の解決策は次のとおりです。また、上記のように、カスタム例外レンダラーを使用していますが、カスタム例外は使用していません。デフォルトのエラー応答は、次のような 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 トークンを返したいとします。これにより、例外がスローされる前に既存のトークンが期限切れになった場合、次に要求を試行するときにブラックホールに陥ることがありません。CSRF 保護の詳細については、セキュリティ コンポーネントのドキュメントを参照してください。
  • app/Lib/Error に新しいクラスを作成します。デフォルトのレンダラーを拡張することも、拡張しないこともできます。いくつかの小さな変更を加えて、例をシンプルに保ちたいので、拡張しています。
  • 返される JSON オブジェクトを作成するためにデフォルトのレンダラーが使用するメソッドをオーバーライドします。これはRequest Handler Componentを介して行われ、ベスト プラクティスに準拠しています。実際、デフォルトのレンダラーは同じことを行います。
  • 物事を DRY に保つための新しいプライベート メソッド。
  • 本番環境でカスタム エラー メッセージが表示されないという問題に対する私の解決策は、オプションの構成キーを追加することです。デフォルトでは、このクラスは本番環境で一般的なメッセージを表示しますが、デバッグが 0 に設定されていて、特定のエラー メッセージが必要な場合:Configure::write('detailed_exceptions', 1);
  • 新しいトークンが存在する場合は、応答に追加します。私の場合、すでにController::setAppController の beforeFilter メソッドで新しいトークンを呼び出しているので、$this->controller->viewVars. これを達成する方法は他にもたくさんあると思います。

これで、応答は次のようになります。

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

任意のタイプの追加データを、渡された配列に追加してController::set、同じ結果を得ることができます。

于 2013-07-10T18:58:46.440 に答える
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);
?>

この場合、私の例外が呼び出されます

テスト例外

次のように定義されます。

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

$code = 2json 応答のカスタム エラー コード 2, があります。ajax 応答は、次の json データでエラー 500 をキャストします。

{"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
});
于 2013-01-14T12:45:18.433 に答える
0

クックブック で説明されているように、CakeExceptions を使用できます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);
}
//...

お役に立てれば :)

(デバッグ モードを上書きせずに)プロダクション モードでカスタム エラーを使用する方法を誰かが知っていれば、私はとても幸せです!

于 2012-08-03T11:22:13.930 に答える