ThunderBirdsX3
ThunderBirdsX3

Reputation: 588

API Server always response " No 'Access-Control-Allow-Origin'"

I write back-end with laravel. And try to call api from IONIC use @angular/http.

In back-end serer, I already add Access-Control-Allow-Origin in middleware and response.

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');

Response.

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',
      ]);

IONIC

  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 api with 'Content-Type' : 'application/json' it always response error.

XMLHttpRequest cannot load http://myurl.local/api/login. Response to preflight request doesn't pass access control check: No '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 get any errors.

But when i try to see input $request->all(). Data i got is '{"username":"XXXXXXXXXX","password":"XXXXXXXXXX"}' => NULL.

With postman is fine. I really try a lot of way to solve this problem, But I can't.

What wrong?

Upvotes: 3

Views: 4807

Answers (2)

ThunderBirdsX3
ThunderBirdsX3

Reputation: 588

Yeahhhh!!! Finally, I can solve this. 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');

  }

In IONIC change header to.

headers = new Headers(
{
  'Content-Type' : 'application/json'
});

And it will not work until you add options route. (In my case, Because I am not use 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 try to use __construct(). But it not work.

Upvotes: 7

sideshowbarker
sideshowbarker

Reputation: 87984

In your Laravel code that processes requests you need to add handling for OPTIONS requests:

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 api with 'Content-Type' : 'application/json' it always response error.

But if I change 'Content-Type' to 'application/x-www-form-urlencoded'. I didn't get any errors.

The application/json content-type triggers browsers to do a CORS preflight OPTIONS request.

https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests has more details.

With postman is fine.

Postman can freely make cross-origin requests without restrictions. But browsers will not allow your frontend JavaScript code to access the response from a cross-origin request unless the response indicates that the server the request is sent is to is opting-in to receiving cross-origin requests.

And if your request is one that triggers browsers to do a CORS preflight OPTIONS request, the server the request is sent to must be configured to respond to the OPTIONS request in the right way. That’s why you need to add additional handling in your Laravel code for OPTIONS requests.

If the server doesn’t respond to the OPTIONS preflight in the right way, the browser will stop there and never get around to doing the POST request you’re actually trying to send.

Upvotes: 1

Related Questions