Laravel/React:barryvdh/laravel-cors 处理预检 HTTP OPTIONS 请求
Posted
技术标签:
【中文标题】Laravel/React:barryvdh/laravel-cors 处理预检 HTTP OPTIONS 请求【英文标题】:Laravel/React: barryvdh/laravel-cors handling preflight HTTP OPTIONS request 【发布时间】:2019-08-29 02:21:41 【问题描述】:刚刚开始使用barryvdh/laravel-cors
。我有一个在端口 8000 上运行的服务器端应用程序,它通过 Laravel Passport 对用户进行身份验证,而我的 react.js 客户端应用程序在端口 3000 上运行。现在我正在尝试让“登录”操作正常工作。
当我提供正确的凭据时,客户端会发回一个令牌,状态为 200。当凭据无效时,会返回 401。到目前为止这么好。但是,如果我在表单中只提供电子邮件而没有密码,我会收到以下与 CORS 相关的错误:
抛出错误时,会发生以下网络调用:
我在客户端的登录:
login = (email, password) =>
console.log(email);
fetch("http://localhost:8000/api/auth/login",
method: 'POST',
body: JSON.stringify(
'email': email,
'password': password
),
headers:
'Content-Type': 'application/json'
)
.then(res => res.json())
.then(response =>
console.log(response['access_token']); //with correct credentials this is logged out and set in local storage
localStorage.setItem('access_token', response['access_token']);
)
.catch(error => console.error('Error: ', error));
服务器端:
public function login(Request $request)
$request->validate([
'email' => 'required|string|email',
'password' => 'required|string',
'remember_me' => 'boolean'
]);
$credentials = request(['email', 'password']);
if(!Auth::attempt($credentials))
return response()->json([
'message' => 'Unauthorized'
], 401);
$user = $request->user();
$tokenResult = $user->createToken('Personal Access Token');
$token = $tokenResult->token;
if ($request->remember_me)
$token->expires_at = Carbon::now()->addWeeks(1);
$token->save();
return response()->json([
'access_token' => $tokenResult->accessToken,
'token_type' => 'Bearer',
'expires_at' => Carbon::parse(
$tokenResult->token->expires_at
)->toDateTimeString()
]);
cors.php
(从 barryvdh/laravel-cors 包发布):
return [
'supportsCredentials' => false,
'allowedOrigins' => ['*'],
'allowedOriginsPatterns' => [],
'allowedHeaders' => ['*'],
'allowedMethods' => ['*'],
'exposedHeaders' => [],
'maxAge' => 0,
];
api.php
:
Route::group(['prefix' => 'auth',], function ()
Route::post('login', 'AuthController@login');
Route::post('register', 'AuthController@register');
Route::get('register/activate/token', 'AuthController@registerActivate');
Route::group(['middleware' => 'auth:api'], function()
Route::get('logout', 'AuthController@logout');
Route::get('user', 'AuthController@user');
);
);
Kernel.php
:
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
// \Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'api' => [
\Barryvdh\Cors\HandleCors::class,
'throttle:60,1',
'bindings',
],
];
protected $middleware = [
\Barryvdh\Cors\HandleCors::class,
\App\Http\Middleware\CheckForMaintenanceMode::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
\App\Http\Middleware\TrustProxies::class
];
通过邮递员发出相同的 POST 请求(向/api/auth/login
发送一个不包含密码的请求)我收到了预期的错误消息:
"message": "The given data was invalid.",
"errors":
"password": [
"The password field is required."
]
但是,通过 react 客户端应用程序进行此操作,会引发屏幕截图中的错误。我猜这与浏览器作为 CORS 工作方式的一部分发送的预检 HTTP OPTIONS 请求有关。
我该如何纠正这个问题?我希望为状态返回 401,并让反应客户端在密码为空的情况下获得 Postman 收到的相同 JSON 消息。根据该 POST 请求的有效负载,出现与 CORS 相关的错误似乎很奇怪。这是否意味着服务器和/或客户端没有正确设置 CORS?
【问题讨论】:
laravel 和 react 应用都需要正确发送 CORS 头。如果您可以避免 CORS 重定向,那么处理起来会容易得多 我以为只有服务器端需要设置 CORS 相关的标头。客户端需要设置哪些标头?我认为我无法避免 CORS 重定向 在这一点上看起来很棒,您能否在您的Kernel.php
中添加config/app.php
内容和中间件部分?
我看到\Barryvdh\Cors\HandleCors::class,
在$middleware
和$middlewareGroups
中都声明了,您可以尝试从$middlewareGroups
部分中删除它吗,另一件事,我注意到很多人有这个问题,它似乎与包的版本有关,你使用的是什么版本?看看这个问题:link1, link2
不客气,我会添加这个作为答案。
【参考方案1】:
好像是你的后端发生错误时抛出的错误。
正如docs中提到的:
发生错误时,中间件未完全运行。所以当 发生这种情况,您不会看到实际结果,但会得到一个 CORS 而是错误。
这个issue 帮助找出了错误的根源
【讨论】:
【参考方案2】:首先是班级成员:
protected $middleware
将为api
和web
应用中间件
发件人 laravel.com/docs/5.8/middleware#registering-middleware
如果您希望在对应用程序的每个 HTTP 请求期间运行中间件,请在 app/Http/Kernel.php 类的 $middleware 属性中列出中间件类。
另请参阅: barryvdh/laravel-cors#global-usage
因此,请尝试通过删除以下内容来注册您的中间件:
\Barryvdh\Cors\HandleCors::class
属于您的'api'
中间件组。
出于逻辑目的,重构您的protected $middleware
:
protected $middleware = [
\App\Http\Middleware\CheckForMaintenanceMode::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
\App\Http\Middleware\TrustProxies::class,
\Barryvdh\Cors\HandleCors::class,
];
【讨论】:
以上是关于Laravel/React:barryvdh/laravel-cors 处理预检 HTTP OPTIONS 请求的主要内容,如果未能解决你的问题,请参考以下文章
Laravel 5.4 laravel-elixir-webpack-react
如何使用 Laravel + React 检查上传文件的类型?
Laravel - React,强制 Axios 进行拒绝/捕获
在 Laravel 5.7 React 应用程序中,收到错误:“classProperties”当前未启用