如何在 Laravel 5.1 中强制 FormRequest 返回 json?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/31507849/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to force FormRequest return json in Laravel 5.1?
提问by Chung
I'm using FormRequestto validate from which is sent in an API call from my smartphone app. So, I want FormRequest alway return json when validation fail.
我正在使用 FormRequest来验证从我的智能手机应用程序的 API 调用中发送的信息。所以,我希望 FormRequest 在验证失败时总是返回 json。
I saw the following source code of Laravel framework, the default behaviour of FormRequest is return json if reqeust is Ajax or wantJson.
我看到如下Laravel框架的源码,如果reqeust是Ajax或者wantJson,FormRequest的默认行为是return json。
//Illuminate\Foundation\Http\FormRequest class
/**
* Get the proper failed validation response for the request.
*
* @param array $errors
* @return \Symfony\Component\HttpFoundation\Response
*/
public function response(array $errors)
{
if ($this->ajax() || $this->wantsJson()) {
return new JsonResponse($errors, 422);
}
return $this->redirector->to($this->getRedirectUrl())
->withInput($this->except($this->dontFlash))
->withErrors($errors, $this->errorBag);
}
I knew that I can add Accept= application/json
in request header. FormRequest will return json. But I want to provide an easier way to request my API by support json in default without setting any header. So, I tried to find some options to force FormRequest response json in Illuminate\Foundation\Http\FormRequest
class. But I didn't find any options which are supported in default.
我知道我可以添加Accept= application/json
请求标头。FormRequest 将返回 json。但是我想提供一种更简单的方法来通过默认支持 json 来请求我的 API,而无需设置任何标头。所以,我试图在Illuminate\Foundation\Http\FormRequest
课堂上找到一些强制 FormRequest 响应 json 的选项。但是我没有找到任何默认支持的选项。
Solution 1 : Overwrite Request Abstract Class
解决方案 1:覆盖请求抽象类
I tried to overwrite my application request abstract class like followings:
我试图覆盖我的应用程序请求抽象类,如下所示:
<?php
namespace Laravel5Cg\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Http\JsonResponse;
abstract class Request extends FormRequest
{
/**
* Force response json type when validation fails
* @var bool
*/
protected $forceJsonResponse = false;
/**
* Get the proper failed validation response for the request.
*
* @param array $errors
* @return \Symfony\Component\HttpFoundation\Response
*/
public function response(array $errors)
{
if ($this->forceJsonResponse || $this->ajax() || $this->wantsJson()) {
return new JsonResponse($errors, 422);
}
return $this->redirector->to($this->getRedirectUrl())
->withInput($this->except($this->dontFlash))
->withErrors($errors, $this->errorBag);
}
}
I added protected $forceJsonResponse = false;
to setting if we need to force response json or not. And, in each FormRequest which is extends from Request abstract class. I set that option.
protected $forceJsonResponse = false;
如果我们需要强制响应json,我添加了设置。并且,在从 Request 抽象类扩展的每个 FormRequest 中。我设置了那个选项。
Eg: I made an StoreBlogPostRequest and set $forceJsoResponse=true
for this FormRequest and make it response json.
例如:我创建了一个 StoreBlogPostRequest 并$forceJsoResponse=true
为此 FormRequest设置并使其响应 json。
<?php
namespace Laravel5Cg\Http\Requests;
use Laravel5Cg\Http\Requests\Request;
class StoreBlogPostRequest extends Request
{
/**
* Force response json type when validation fails
* @var bool
*/
protected $forceJsonResponse = true;
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'title' => 'required|unique:posts|max:255',
'body' => 'required',
];
}
}
Solution 2: Add an Middleware and force change request header
解决方案 2:添加中间件并强制更改请求标头
I build a middleware like followings:
我构建了一个如下所示的中间件:
namespace Laravel5Cg\Http\Middleware;
use Closure;
use Symfony\Component\HttpFoundation\HeaderBag;
class AddJsonAcceptHeader
{
/**
* Add Json HTTP_ACCEPT header for an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
$request->server->set('HTTP_ACCEPT', 'application/json');
$request->headers = new HeaderBag($request->server->getHeaders());
return $next($request);
}
}
It 's work. But I wonder is this solutions good? And are there any Laravel Way to help me in this situation ?
这是工作。但我想知道这个解决方案好吗?在这种情况下,是否有任何 Laravel 方式可以帮助我?
回答by Bouke Versteegh
It boggles my mind why this is so hard to do in Laravel. In the end, based on your idea to override the Request class, I came up with this.
我很困惑为什么这在 Laravel 中很难做到。最后,根据你覆盖 Request 类的想法,我想出了这个。
app/Http/Requests/ApiRequest.php
app/Http/Requests/ApiRequest.php
<?php
namespace App\Http\Requests;
class ApiRequest extends Request
{
public function wantsJson()
{
return true;
}
}
Then, in every controller just pass \App\Http\Requests\ApiRequest
然后,在每个控制器中通过 \App\Http\Requests\ApiRequest
public function index(ApiRequest $request)
public function index(ApiRequest $request)
回答by SimonDepelchin
I know this post is kind of old but I just made a Middleware that replaces the "Accept" header of the request with "application/json". This makes the wantsJson()
function return true
when used. (This was tested in Laravel 5.2 but I think it works the same in 5.1)
我知道这篇文章有点旧,但我刚刚制作了一个中间件,用“application/json”替换了请求的“Accept”标头。这使得wantsJson()
函数true
在使用时返回。(这是在 Laravel 5.2 中测试过的,但我认为它在 5.1 中的工作原理相同)
Here's how you implement that :
这是你如何实现的:
Create the file
app/Http/Middleware/Jsonify.php
namespace App\Http\Middleware; use Closure; class Jsonify { /** * Change the Request headers to accept "application/json" first * in order to make the wantsJson() function return true * * @param \Illuminate\Http\Request $request * @param \Closure $next * * @return mixed */ public function handle($request, Closure $next) { $request->headers->set('Accept', 'application/json'); return $next($request); } }
Add the middleware to your
$routeMiddleware
table of yourapp/Http/Kernel.php
fileprotected $routeMiddleware = [ 'auth' => \App\Http\Middleware\Authenticate::class, 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class, 'jsonify' => \App\Http\Middleware\Jsonify::class ];
Finally use it in your
routes.php
as you would with any middleware. In my case it looks like this :Route::group(['prefix' => 'api/v1', 'middleware' => ['jsonify']], function() { // Routes });
创建文件
app/Http/Middleware/Jsonify.php
namespace App\Http\Middleware; use Closure; class Jsonify { /** * Change the Request headers to accept "application/json" first * in order to make the wantsJson() function return true * * @param \Illuminate\Http\Request $request * @param \Closure $next * * @return mixed */ public function handle($request, Closure $next) { $request->headers->set('Accept', 'application/json'); return $next($request); } }
将中间件添加到文件
$routeMiddleware
表中app/Http/Kernel.php
protected $routeMiddleware = [ 'auth' => \App\Http\Middleware\Authenticate::class, 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class, 'jsonify' => \App\Http\Middleware\Jsonify::class ];
最后在您的
routes.php
任何中间件中使用它。就我而言,它看起来像这样:Route::group(['prefix' => 'api/v1', 'middleware' => ['jsonify']], function() { // Routes });
回答by Afraz Ahmad
if your request has either X-Request-With: XMLHttpRequestheader or accept content type as application/jsonFormRequest will automatically return a json response containing the errors with a status of 422.
如果您的请求具有X-Request-With: XMLHttpRequest标头或接受内容类型为 application/jsonFormRequest 将自动返回包含状态为 422 的错误的 json 响应。
回答by T30
Based on ZeroOne's response, if you're using Form Request validationyou can override the failedValidation method to always return json in case of validation failure.
根据ZeroOne 的响应,如果您使用表单请求验证,您可以覆盖 failedValidation 方法以在验证失败的情况下始终返回 json。
The good thing about this solution, is that you're not overriding all the responses to return json, but just the validation failures. So for all the other Php exceptions you'll still see the friendly Laravel error page.
这个解决方案的好处是,您不会覆盖所有返回 json 的响应,而只是覆盖验证失败。因此,对于所有其他 Php 异常,您仍然会看到友好的 Laravel 错误页面。
namespace App\Http\Requests;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Http\Exceptions\HttpResponseException;
use Symfony\Component\HttpFoundation\Response;
class InventoryRequest extends FormRequest
{
protected function failedValidation(Validator $validator)
{
throw new HttpResponseException(response($validator->errors(), Response::HTTP_UNPROCESSABLE_ENTITY));
}
回答by ZeroOne
i just override the failedValidation
function
我只是覆盖了这个failedValidation
功能
protected function failedValidation(Validator $validator)
{
if ($this->wantsJson()) {
// flatten all the message
$collection = collect($validator->errors())->flatten()->values()->all();
throw new HttpResponseException(Response::error('Validation Error', $collection));
}
parent::failedValidation($validator);
}
So output sample:
所以输出样本:
{
"error": true,
"message": "Validation Error",
"reference": [
"The device id field is required.",
"The os version field is required.",
"The apps version field is required."
],
}