Skip to content

Commit ffee8c4

Browse files
committed
fix: return 404 instead of 500 for non-existent routes
- Set default response format to JSON for API - Remove forced HTML format in RequestDispatcher - Handle HttpException with correct status codes
1 parent 9beb4cb commit ffee8c4

File tree

2 files changed

+62
-20
lines changed

2 files changed

+62
-20
lines changed

examples/app-api/config/web.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
'application/json' => 'yii\web\JsonParser',
1515
],
1616
],
17+
'response' => [
18+
'format' => \yii\web\Response::FORMAT_JSON,
19+
],
1720
'session' => [
1821
'class' => \Dacheng\Yii2\Swoole\Session\CoroutineSession::class,
1922
'redis' => 'redis',
@@ -25,9 +28,6 @@
2528
'identityClass' => \app\models\UserIdentity::class,
2629
'enableAutoLogin' => false,
2730
],
28-
'errorHandler' => [
29-
'errorAction' => 'site/error',
30-
],
3131
'log' => [
3232
'traceLevel' => YII_DEBUG ? 3 : 0,
3333
'flushInterval' => 1,

src/Server/RequestDispatcher.php

Lines changed: 59 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@ public function dispatch(Request $request, Response $response, SwooleCoroutineHt
7474

7575
$yiiResponse = $app->getResponse();
7676
$yiiResponse->clear();
77-
$yiiResponse->format = YiiResponse::FORMAT_HTML;
7877
$this->prepareLogger($app);
7978

8079
try {
@@ -139,7 +138,6 @@ public function dispatch(Request $request, Response $response, SwooleCoroutineHt
139138
$yiiResponse->_cookies = null;
140139
}
141140
$yiiResponse->clear();
142-
$yiiResponse->format = YiiResponse::FORMAT_HTML;
143141

144142
// Clear request data
145143
if ($yiiRequest instanceof YiiRequest) {
@@ -191,28 +189,38 @@ private function handleExceptionWithYii(Throwable $exception, Application $app,
191189
$errorHandler->exception = $exception;
192190
$errorHandler->logException($exception);
193191

194-
$bufferLevel = ob_get_level();
195-
ob_start();
196-
try {
197-
$this->invokeErrorHandlerRenderException($errorHandler, $exception);
198-
$bufferedOutput = ob_get_contents() ?: '';
199-
} finally {
200-
while (ob_get_level() > $bufferLevel) {
201-
ob_end_clean();
202-
}
203-
204-
$errorHandler->exception = null;
205-
}
206-
207192
$yiiResponse = $app->getResponse();
208193
if ($yiiResponse->isSent) {
209194
$yiiResponse->isSent = false;
210195
}
211196

212-
if ($yiiResponse->content === null) {
213-
$yiiResponse->content = $bufferedOutput;
197+
if ($exception instanceof \yii\web\HttpException) {
198+
$yiiResponse->setStatusCode($exception->statusCode);
199+
} else {
200+
$yiiResponse->setStatusCode(500);
201+
}
202+
203+
if ($yiiResponse->format === YiiResponse::FORMAT_JSON) {
204+
$yiiResponse->data = $this->convertExceptionToArray($exception, $errorHandler);
205+
} else {
206+
$bufferLevel = ob_get_level();
207+
ob_start();
208+
try {
209+
$this->invokeErrorHandlerRenderException($errorHandler, $exception);
210+
$bufferedOutput = ob_get_contents() ?: '';
211+
} finally {
212+
while (ob_get_level() > $bufferLevel) {
213+
ob_end_clean();
214+
}
215+
}
216+
217+
if ($yiiResponse->content === null) {
218+
$yiiResponse->content = $bufferedOutput;
219+
}
214220
}
215221

222+
$errorHandler->exception = null;
223+
216224
if ($this->isWritable($swooleResponse)) {
217225
$this->finalizeResponse($swooleResponse, $yiiResponse);
218226
}
@@ -225,6 +233,40 @@ private function handleExceptionWithYii(Throwable $exception, Application $app,
225233
}
226234
}
227235

236+
private function convertExceptionToArray(Throwable $exception, ErrorHandler $errorHandler): array
237+
{
238+
if (!defined('YII_DEBUG') || !YII_DEBUG) {
239+
if (!($exception instanceof \yii\base\UserException) && !($exception instanceof \yii\web\HttpException)) {
240+
$exception = new \yii\web\HttpException(500, Yii::t('yii', 'An internal server error occurred.'));
241+
}
242+
}
243+
244+
$array = [
245+
'name' => ($exception instanceof \yii\base\Exception || $exception instanceof \yii\base\ErrorException)
246+
? $exception->getName()
247+
: 'Exception',
248+
'message' => $exception->getMessage(),
249+
'code' => $exception->getCode(),
250+
];
251+
252+
if ($exception instanceof \yii\web\HttpException) {
253+
$array['status'] = $exception->statusCode;
254+
}
255+
256+
if (defined('YII_DEBUG') && YII_DEBUG) {
257+
$array['type'] = get_class($exception);
258+
$array['file'] = $exception->getFile();
259+
$array['line'] = $exception->getLine();
260+
$array['stack-trace'] = explode("\n", $exception->getTraceAsString());
261+
}
262+
263+
if (($prev = $exception->getPrevious()) !== null) {
264+
$array['previous'] = $this->convertExceptionToArray($prev, $errorHandler);
265+
}
266+
267+
return $array;
268+
}
269+
228270
private function invokeErrorHandlerRenderException(ErrorHandler $errorHandler, Throwable $exception): void
229271
{
230272
if (self::$renderExceptionMethod === null) {

0 commit comments

Comments
 (0)