我想做一些与此非常相似的事情,但在 CakePHP 世界中用于 AJAX 请求。目前我正在这样做:
$this->autoRender = false;
$this->response->statusCode(500);
它基于此。但是,此解决方案不允许我像 Rails 示例中那样包含自定义消息,因此,在我的客户端错误处理程序中,我可以显示 500 错误响应中包含的消息。
我将如何在 CakePHP 中实现与 Ruby on Rails 示例相同的功能?
如上所述,异常是在 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');
所以这是它的工作原理:
Configure::write('detailed_exceptions', 1);
Controller::set
on the new token in the beforeFilter method of AppController, so it is available in $this->controller->viewVars
. There are probably dozens of other ways of accomplishing this.Now your response looks like this:
{
"name":"The request has been black-holed",
"url":"\/users\/login.json",
"csrf_token":"1279f22f9148b6ff30467abaa06d83491c38e940"
}
Any additional data, of any type can be added to the array passed to Controller::set
for the same result.
在使用 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);
}
}
我的 json 响应有一个自定义错误代码 2 $code = 2
,。ajax 响应将使用以下 json 数据投射错误 500:
{"errorCode":"2","errorMessage":"My custom exception."}
显然,您还需要从控制器中抛出异常:
throw new TestException();
这可能有点超出范围,但为了处理 JQuery 中的 ajax 错误响应,我使用:
$(document).ajaxError(function (event, jqXHR, ajaxSettings, thrownError) {
//deal with my json error
});
您可以按照 Cookbook 中的说明使用 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);
}
//...
希望这可以帮助 :)
如果有人知道如何在生产模式下使用自定义错误(不覆盖调试模式),我会非常高兴!