【问题标题】:How to return AJAX errors from a Laravel controller?如何从 Laravel 控制器返回 AJAX 错误?
【发布时间】:2016-05-21 15:34:08
【问题描述】:

我正在使用 Laravel 5 构建一个 REST API。

在 Laravel 5 中,您可以继承 App\Http\Requests\Request 来定义在处理特定路由之前必须满足的验证规则。例如:

<?php

namespace App\Http\Requests;

use App\Http\Requests\Request;

class BookStoreRequest extends Request {

    public function authorize() {
        return true;
    }

    public function rules() {
        return [
            'title' => 'required',
            'author_id' => 'required'
        ];
    }
}

如果客户端通过 AJAX 请求加载相应的路由,BookStoreRequest 发现请求不满足规则,它会自动将错误作为 JSON 对象返回。例如:

{
  "title": [
    "The title field is required."
  ]
}

但是,Request::rules() 方法只能验证输入——即使输入有效,在请求已被接受并移交给控制器之后,也可能会出现其他类型的错误。例如,假设控制器出于某种原因需要将新书信息写入文件——但文件无法打开:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

use App\Http\Requests;
use App\Http\Controllers\Controller;

use App\Http\Requests\BookCreateRequest;

class BookController extends Controller {

    public function store( BookStoreRequest $request ) {

        $file = fopen( '/path/to/some/file.txt', 'a' );

        // test to make sure we got a good file handle
        if ( false === $file ) {
            // HOW CAN I RETURN AN ERROR FROM HERE?
        }

        fwrite( $file, 'book info goes here' );
        fclose( $file );

        // inform the browser of success
        return response()->json( true );

    }

}

显然,我可以die(),但这太丑了。我希望以与验证错误相同的格式返回我的错误消息。像这样:

{
  "myErrorKey": [
    "A filesystem error occurred on the server. Please contact your administrator."
  ]
}

我可以构建自己的 JSON 对象并返回它——但 Laravel 肯定支持这一点。

最好/最干净的方法是什么?或者有没有更好的方法从 Laravel REST API 返回运行时(而不是验证时)错误?

【问题讨论】:

  • 你为什么不能做一个return response()-&gt;json( ['error'=&gt;'Your custom message'] );
  • 可以构建自定义json响应类
  • return response()-&gt;json() 会返回 200 OK。我想使用适当的非 200 响应代码(例如 500 Internal Server Error)。是的,我也可以手动编写代码——我只是假设 Laravel 已经提供了一种内置的、更结构化的方式来执行此操作。也许这是一个不正确的假设。
  • 为此考虑github.com/dingo/api
  • @greenie2600 :你得到解决方案了吗?

标签: laravel laravel-5 laravel-5.2


【解决方案1】:

您可以在 json 响应中设置状态码,如下所示:

return Response::json(['error' => 'Error msg'], 404); // Status code here

或者只是使用辅助函数:

return response()->json(['error' => 'Error msg'], 404); // Status code here

【讨论】:

  • 使用 response() 函数,而不是 $response()
【解决方案2】:

您可以通过多种方式做到这一点。

首先,您可以通过提供状态码来使用简单的response()-&gt;json()

return response()->json( /** response **/, 401 );

或者,以更复杂的方式来确保每个错误都是 json 响应,您可以设置异常处理程序来捕获特殊异常并返回 json。

打开App\Exceptions\Handler 并执行以下操作:

class Handler extends ExceptionHandler
{
    /**
     * A list of the exception types that should not be reported.
     *
     * @var array
     */
    protected $dontReport = [
        HttpException::class,
        HttpResponseException::class,
        ModelNotFoundException::class,
        NotFoundHttpException::class,
        // Don't report MyCustomException, it's only for returning son errors.
        MyCustomException::class
    ];

    public function render($request, Exception $e)
    {
        // This is a generic response. You can the check the logs for the exceptions
        $code = 500;
        $data = [
            "error" => "We couldn't hadle this request. Please contact support."
        ];

        if($e instanceof MyCustomException) {
            $code = $e->getStatusCode();
            $data = $e->getData();
        }

        return response()->json($data, $code);
    }
}

这将为应用程序中抛出的任何异常返回一个 json。 现在,我们创建MyCustomException,例如在app/Exceptions中:

class MyCustomException extends Exception {

    protected $data;
    protected $code;

    public static function error($data, $code = 500)
    {
        $e = new self;
        $e->setData($data);
        $e->setStatusCode($code);

        throw $e;
    }

    public function setStatusCode($code)
    {
        $this->code = $code;
    }

    public function setData($data)
    {
        $this->data = $data;
    }


    public function getStatusCode()
    {
        return $this->code;
    }

    public function getData()
    {
        return $this->data;
    }
}

我们现在可以只使用MyCustomException 或任何扩展MyCustomException 的异常来返回一个json 错误。

public function store( BookStoreRequest $request ) {

    $file = fopen( '/path/to/some/file.txt', 'a' );

    // test to make sure we got a good file handle
    if ( false === $file ) {
        MyCustomException::error(['error' => 'could not open the file, check permissions.'], 403);

    }

    fwrite( $file, 'book info goes here' );
    fclose( $file );

    // inform the browser of success
    return response()->json( true );

}

现在,不仅通过MyCustomException 抛出的异常将返回 json 错误,而且任何其他一般抛出的异常都将返回。

【讨论】:

    【解决方案3】:

    一个简单的方法是在控制器中使用abort() 方法。这将返回一个错误,该错误将被 ajax error:function(){}

    控制器示例

    public function boost_reputation(Request $request){
        
            $page_owner = User::where('id', $request->page_owner_id)->first();
    
            // user needs to login to boost reputation
            if(!Auth::user()){
                toast('Sorry, you need to login first.','info');
                abort();
            }
    
            // page owner cannot boost his own reputation
            if(Auth::user() == $page_owner){
                toast("Sorry, you can't boost your own reputation.",'info');
                abort();
            }
    }
    

    Ajax 示例

    $('.reputation-btn').on('click',function(event){
    
       var btn = this;
       var route = "{{ route('boost_reputation') }}";
       var csrf_token = '{{ csrf_token() }}';
       var id = '{{ $page_owner->id }}';
    
       $.ajax({
         method: 'POST',
         url: route,
         data: {page_owner_id:id, _token:csrf_token},
    
         success:function(data) {
            ...your success code
         },
         error: function () {
            ...your error code
         }
    
       });
    });
    

    更多信息:https://laravel.com/docs/7.x/errors

    【讨论】:

      猜你喜欢
      • 2020-08-13
      • 2020-11-12
      • 1970-01-01
      • 2018-04-07
      • 2014-12-23
      • 2019-07-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多