由於目前網站後台使用 Laravel 標準的 view 製作,但前台將使用 API 串接,這時候若沒有做錯誤處理就會發現 Laravel 拋出的錯誤訊息夾帶著 view 視圖的錯誤訊息,有心人士就可以透過這些訊息得知你的 API 是用哪種方式生成,利用漏洞來攻擊你的 API。
統一 API 資料及訊息格式
在 app\Traits 目錄,建立 ApiResponser.php 檔案。
<?php
namespace App\Traits;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Cache;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Validator;
use Illuminate\Pagination\LengthAwarePaginator;
trait ApiResponser
{
//成功時回應格式
protected function successResponse($total, $data, $message = null, $code = 200)
{
return response()->json([
'status'=> 'Success',
'message' => $message,
'total' => $total,
'data' => $data
], $code);
}
//失敗時回應格式
protected function errorResponse($message = null, $code)
{
return response()->json([
'status'=>'Error',
'message' => $message,
], $code);
}
}
修改 app\Http\Controller\Controller.php 或者另外建立一支延伸的 ApiController.php,基本上都是一樣的。
<?php
namespace App\Http\Controllers;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Routing\Controller as BaseController;
use App\Traits\ApiResponser;
class Controller extends BaseController
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests, ApiResponser;
}
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Traits\ApiResponser;
class ApiController extends Controller
{
use ApiResponser;
}
在 API Controller 中使用 ApiResponser
//之前寫法
return response()->json(['status' => 'Success','message' => '成功','total' => $products->count(), 'data' => $products],200);
return response()->json(['status' => 'Error', 'message' => '參數不存在/參數錯誤'],400);
//使用 ApiResponser 寫法
return $this->successResponse($products->count(), $products, '成功');
return $this->errorResponse('參數不存在/參數錯誤', 400);
錯誤處理
修改 app\Exceptions\Handler.php
<?php
namespace App\Exceptions;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Throwable;
use App\Traits\ApiResponser;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Validation\ValidationException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
use Symfony\Component\HttpKernel\Exception\HttpException;
class Handler extends ExceptionHandler
{
use ApiResponser;
/**
* Register the exception handling callbacks for the application.
*
* @return void
*/
public function register()
{
$this->reportable(function (Throwable $e) {
//
});
// Laravel 8.x 改成此種註冊方式
$this->renderable(function (Throwable $e) {
return $this->handleException($e);
});
}
//建立 handleException function
public function handleException( Throwable $e){
if ($e instanceof MethodNotAllowedHttpException) {
return $this->errorResponse('The specified method for the request is invalid', 405);
}
if ($e instanceof NotFoundHttpException) {
return $this->errorResponse('The specified URL cannot be found', 404);
}
if ($e instanceof HttpException) {
return $this->errorResponse($e->getMessage(), $e->getStatusCode());
}
if (config('app.debug')) {
return parent::render($request, $e);
}
return $this->errorResponse('Unexpected Exception. Try later', 500);
}
}
這樣一來,所有的錯誤都將返回成文字型態錯誤訊息,讓人無法探測你的網站 或 API 的任何資訊。
測試