使用Laravel 5.6创建了一个API,并且所有端点均可与Postman一起使用。当我开始开发Angular 6应用程序时,问题就开始了。由于我在本地工作,因此无论使用哪种http方法(httpClient),我都开始在Chrome中出现CORS错误。因此,我在Laravel中创建了一个中间件来处理CORS请求。一切开始按预期工作,所以我想...现在我面临其他问题。
我正在使用Laravel的默认控制器操作执行CRUD任务,因此我主要使用资源路由(Route :: resource)。对于自定义方法,我使用的是Route :: post()。
现在,奇怪的是我可以发送发布请求用于自定义方法(Route :: post),但不能发送到资源路由。
示例:
//post requests to custom routes work as expected
Route::post('users/block', 'API\UserController@toggleBlock');
Route::post('users/access', 'API\UserController@sendAccess');
//post requests to resource routes nothing happens
Route::resource('settings', 'API\SettingController');
Route::resource('products', 'API\ProductController');
如果我将路线更改为以下内容:
Route::get('settings', 'API\SettingController@index'); //works!
Route::post('settings', 'API\SettingController@store'); //nothing happens!!
Route::post('settings/bazinga', 'API\SettingController@store'); //works!!
因此,据我所知,即使http方法不同,我也无法使用相同的URI。
这是我的CORS中间件:
public function handle($request, Closure $next)
{
//apply cors only to api routes
if (Request::segment(1) == 'api') {
header("Access-Control-Allow-Origin: *");
// ALLOW OPTIONS METHOD
$headers = [
'Access-Control-Allow-Methods' => 'POST, GET, OPTIONS, PUT, DELETE',
'Access-Control-Allow-Headers' => 'Content-Type, X-Auth-Token, Origin, Authorization, Accept, Cache-Control',
];
if ($request->isMethod("OPTIONS")) {
// The client-side application can set only headers allowed in Access-Control-Allow-Headers
return Response::make('OK', 200, $headers);
}
$response = $next($request);
foreach ($headers as $key => $value) {
$response->header($key, $value);
}
} else {
$response = $next($request);
}
return $response;
}
为什么会这样?这和CORS有关吗?既然一切都能按照Postman的要求进行,那么这可能与CORS有关,对吧?
更新:cURL输出
> curl 'https://api.project.localhost:34430/api/settings' -D -X OPTIONS -H 'pragma: no-cache' -H 'access-control-request-headers: authorization,' -H 'access-control-request-method: POST' -H 'origin: <http://localhost:4200>' -o output.txt
卷曲:(6)无法解析主机:选项
更新#2:角度代码
保存方法:
save(settings: Setting[]): Observable<any> {
const path = 'settings';
const headers = {
'Cache-Control': 'no-cache'
};
const params = { settings: settings };
return new Observable(observer => {
this.api.post(path, params, headers).subscribe(
data => {
// observable execution
observer.next('Save Settings');
observer.complete();
},
error => console.log(error) // error path
);
});
}
发布方法:
post(path: string, params: Object, headers?: any): Observable<ApiResponse> {
const request = this.createRequestObject(path, params, headers);
return this.http.post<ApiResponse>(
request.endPoint,
request.params,
request.httpOptions
);
}
private createRequestObject(path: string, params?: Object, headers?: any): ApiRequest {
if (headers) {
Object.assign(this.headers, headers);
}
const request = new ApiRequest();
request.endPoint = this.endPoint + path;
request.httpOptions = { headers: this.headers };
request.params = params;
return request;
}
更新#3:Chrome开发者工具控制台
获取请求:
发布请求:
注意:当我执行发布请求时,“网络活动”中没有任何反应。
答案 0 :(得分:0)
您可以通过curl或邮递员检查通过OPTION为此端点获得的输出是什么吗?
curl '<path to endpoint>' -X OPTIONS -H 'pragma: no-cache' -H 'access-control-request-headers: authorization,' -H 'access-control-request-method: POST' -H 'origin: <http://localhost:4200>'
类似上述要求?
答案 1 :(得分:0)
此问题是由于传递了和必需的标头。应该维护并从双方(客户端和服务器)传递。
Laravel:
您可以使用软件包https://github.com/barryvdh/laravel-cors并根据要求修改设置。
角度6:您必须阅读https://angular.io/api/common/http/HttpInterceptor。您可以创建拦截器,该拦截器将在客户端处理标头。我附上了样板,您可以在其中检查和使用拦截器。检查给定链接中的答案。 https://stackoverflow.com/a/53350123/3851720
答案 2 :(得分:0)
在角端,在我添加的服务文件中
const httpOptions = {
headers: new HttpHeaders({
'Access-Control-Allow-Origin':'*'
})
};
在装饰之前。
然后在Laravel中以公用文件夹内的index.php结尾, 只需添加下面的标题
header('Access-Control-Allow-Origin: http://localhost:4200');
header('Access-Control-Allow-Methods: GET, POST, PATCH, PUT, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization');