API Server always responds "No" Access-Control-Allow-Origin "
I am writing back end with laravel. And try calling api from IONIC use @angular/http
.
In the back-end serer, I already add Access-Control-Allow-Origin
in middleware and answer.
Middleware.
return $next($request)
->header('Access-Control-Allow-Origin', '*')
->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE')
->header('Access-Control-Allow-Credentials', true)
->header('Access-Control-Allow-Headers', 'Content-Type')
->header('Vary', 'Origin');
Answer.
return response($data, 200)
->withHeaders([
'Content-Type' => 'application/json',
'Access-Control-Allow-Origin' => '*',
'Access-Control-Allow-Methods' => 'GET, POST, PUT, DELETE',
'Access-Control-Allow-Credentials' => true,
'Access-Control-Allow-Headers' => 'Content-Type',
'Vary' => 'Origin',
]);
ION
url: any = 'http://myurl.local/api/';
headers = new Headers(
{
'Accept' : 'application/json',
'Content-Type' : 'application/json',
'Access-Control-Request-Methods' : 'POST'
});
options = new RequestOptions({ headers: this.headers });
login(username, password) {
let data = JSON.stringify({
username : username,
password : password
});
let fullUrl = this.url+'login';
return new Promise((resolve, reject) => {
this.http.post(fullUrl, data, this.options)
.toPromise()
.then((response) =>
{
console.log('API Response : ', response);
resolve(response.json());
})
.catch((error) =>
{
console.error('API Error : ', error.toString());
reject(error.json());
});
});
}
When I call the api with 'Content-Type' : 'application/json'
, it is always responsible for the error.
XMLHttpRequest cannot load http: //myurl.local/api/login . Preflight Request Response Fails Access Control Check: None The Access-Control-Allow-Origin header is present on the requested resource. Origin ' http: // localhost: 8100 ' is therefore not allowed access.
But if I change 'Content-Type'
to 'application/x-www-form-urlencoded'
. I didn't have any errors.
But when I try to see the entrance $request->all()
. Received data - '{"username":"XXXXXXXXXX","password":"XXXXXXXXXX"}' => NULL
.
The postman is all right. I am really trying a lot to solve this problem, but I cannot.
What's wrong?
Yeahhhh !!! Finally I can work it out. God damn it.
In middleware.
public function handle($request, Closure $next)
{
if ($request->getMethod() == "OPTIONS") {
return response(['OK'], 200)
->withHeaders([
'Access-Control-Allow-Origin' => '*',
'Access-Control-Allow-Methods' => 'GET, POST, PUT, DELETE',
'Access-Control-Allow-Credentials' => true,
'Access-Control-Allow-Headers' => 'Authorization, Content-Type',
]);
}
return $next($request)
->header('Access-Control-Allow-Origin', '*')
->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE')
->header('Access-Control-Allow-Credentials', true)
->header('Access-Control-Allow-Headers', 'Authorization, Content-Type');
}
The header changes IONIC to.
headers = new Headers(
{
'Content-Type' : 'application/json'
});
And it won't work until you add a route options
. (In my case, because I am not using Route::resource
)
Route::group(['middleware' => 'AddHeader'], function()
{
Route::post('/login', 'LoginController@index');
Route::options('/login', 'LoginController@index');
});
PS. I have some logic in function index()
I am trying to use __construct()
. But it doesn't work.
In your Laravel code that handles requests, you need to add handling for requests OPTIONS
:
if ($request->getMethod() == "OPTIONS") {
$headers = [
'Access-Control-Allow-Origin' => '*'
'Access-Control-Allow-Methods'=> 'POST, GET',
'Access-Control-Allow-Headers'=> 'Content-Type'
];
return Response::make('OK', 200, $headers);
}
When I call the api with
'Content-Type' : 'application/json'
, it is always responsible for the error.But if I change
'Content-Type'
to'application/x-www-form-urlencoded'
. I didn't have any errors.
application/json
content type triggers browsers to perform CORS previews OPTIONS
.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests has more details.
The postman is fine.
Postman is free to send cross-origin requests without limitation. But browsers will not allow your external JavaScript code to access the response from a cross-origin request, unless the response indicates that the server to which the request is sent is the choice to accept cross-origin requests.
And if your request is the one that triggers browsers to request the OPTIONS
CORS preflight request , the server that the request is sent to must be configured to respond correctly to the request OPTIONS
. This is why you need to add additional processing to your Laravel code for requests OPTIONS
.
If the server does not respond to the preview OPTIONS
correctly, the browser will stop there and never be able to fulfill the request POST
you are actually trying to send.