Php 如何在Laravel 5.1中强制FormRequest返回json?
我正在使用它来验证智能手机应用程序在API调用中发送的消息。因此,我希望FormRequest在验证失败时始终返回json 我看到了以下Laravel框架的源代码,如果Request是Ajax或wantJson,FormRequest的默认行为是返回jsonPhp 如何在Laravel 5.1中强制FormRequest返回json?,php,laravel,laravel-5,laravel-validation,Php,Laravel,Laravel 5,Laravel Validation,我正在使用它来验证智能手机应用程序在API调用中发送的消息。因此,我希望FormRequest在验证失败时始终返回json 我看到了以下Laravel框架的源代码,如果Request是Ajax或wantJson,FormRequest的默认行为是返回json //Illuminate\Foundation\Http\FormRequest class /** * Get the proper failed validation response for the request. * * @
//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);
}
我知道我可以在请求头中添加Accept=application/json
。FormRequest将返回json。但是我想提供一种更简单的方法来请求我的API,默认情况下支持json,而不设置任何头。因此,我尝试在illighted\Foundation\Http\FormRequest
类中找到一些选项来强制FormRequest-response-json。但是我没有找到默认支持的任何选项
解决方案1:覆盖请求抽象类
我试图覆盖我的应用程序请求抽象类,如下所示:
<?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);
}
}
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);
}
}
解决方案2:添加中间件和强制更改请求头
我构建了如下中间件:
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);
}
}
这是工作。但我想知道这个解决方案好吗?在这种情况下,有没有办法帮助我 这让我很困惑,为什么在拉威尔这么难做到。最后,基于您重写请求类的想法,我提出了这个
app/Http/Requests/apirest.php
<?php
namespace App\Http\Requests;
class ApiRequest extends Request
{
public function wantsJson()
{
return true;
}
}
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);
}
}
我知道这篇文章有点陈旧,但我只是制作了一个中间件,用“application/json”替换请求的“Accept”头。这使得wantsJson()
函数在使用时返回true
。(这在Laravel 5.2中进行了测试,但我认为其在5.1中的效果相同)
以下是如何实现这一点:
创建文件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);
}
}
将中间件添加到app/Http/Kernel.php
文件的$routeMiddleware
表中
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);
}
}
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'jsonify' => \App\Http\Middleware\Jsonify::class
];
最后,在routes.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);
}
}
Route::group(['prefix' => 'api/v1', 'middleware' => ['jsonify']], function() {
// Routes
});
如果您的请求具有X-request-With:XMLHttpRequest标题或接受内容类型为application/jsonFormRequest将自动返回包含错误的json响应,状态为422
我只是覆盖了失败验证
功能
protected function failedValidation(Validator $validator)
{
if ($this->wantsJson()) {
throw new HttpResponseException(
Response::error(__('api.validation_error'),
$validator->errors(),
470,
[],
new ValidationException)
);
}
parent::failedValidation($validator);
}
因此,我的自定义输出示例如下所示:
{
"error": true,
"message": "Validation Error",
"reference": [
"The device id field is required.",
"The os version field is required.",
"The apps version field is required."
],
}
顺便说一句:laravel中不存在错误。Im使用MacroTable创建新方法
Response::macro('error', function ($msg = 'Something went wrong', $reference = null, $code = 400, array $headers = [], $exception = null) {
return response()->json(//custom here);
});
基于,如果您使用的是failedValidation方法,那么在验证失败的情况下,您可以重写failedValidation方法以始终返回json
这个解决方案的好处在于,您不会覆盖所有返回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));
}
}
您好,我只是想提出一个建议,既然您要求默认响应类型,那么为什么不在您的handle方法$request->header('accept','application/json')中添加一个中间件并将请求类型添加到json中呢;返回$next($request)代码>有了这些,您就有了进一步扩展的空间,而不必总是覆盖任何MethodsHanks!这是个好主意。我想。我将在上面的问题中更新此实现。我试图设置$request->header('Accept','application/json');在中间件中,但我发现我的请求具有默认的Accept标头“/”,因此我无法覆盖该Accept标头。我没有在我的请求中设置任何内容。这无关紧要,不管您是否在头中设置了默认的accept值,中间件值都将覆盖它$request=$request->header('accept','application/json');返回$next($request)代码>我认为,请求没有被持久化。我找到了覆盖请求头的方法,我们需要设置$request->server并重建headerBag,如下所示:$request->server->set('HTTP_ACCEPT',application/json')$request->headers=newheaderbag($request->server->getHeaders());我也有同样的问题,我想试试这个解决方案。我遇到的问题是,当我的控制器方法隐式加载我的FormRequest实例时,它与Jsonify中间件中修改的请求实例不同,因此WANTSSON实际上被“重置”为false。FormRequest扩展了请求,因此它应该是同一个实例,也许给我看看code@SimonDepelchin这个解决方案类似于我在问题中提到的解决方案2。是的,它有更多的细节和更多的“Laravel方式”imho。这个解决方案更好,因为它以JSON的形式返回所有内容。如果您使用apirest
发出未经授权的请求,它将返回404 html页面,但这将返回401个未经授权的JSON错误。接受:标题中的应用程序/JSON也可能有助于解决此问题。我在测试5.4应用程序时遇到此问题。简单地将这个方法添加到a中就可以做到这一点。“这让我觉得有多难”…“这是一个非常简单的方法”,哈哈,这让我笑了+1它不工作:这样的请求为空$request->all()
这在工作或不工作的二进制意义上工作,但是考虑到这个问题起草得有多好,这是一个真正的解决方案。你能分享Response
class@Manojkiran.AIllumb\Support\Facades\Response.Clear解决方案,非常感谢,在Laravel 6.14上运行良好
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);
}
}