I am working on a REST API using CakePHP 3. I want to enable it publicly, so anyone can mane a call to API. So, I have added cors headers as defined here: http://book.cakephp.org/3.0/en/controllers/request-response.html#setting-cross-origin-request-headers-cors
I have implemented the EventListener on Dispatcher.beforeDispatch and Dispatcher.beforeDispatch to prepare the cors headers.
class ApiResponseHeaders implements EventListenerInterface
{
/**
* Event bindings
*
* @return array
*/
public function implementedEvents()
{
return [
'Dispatcher.beforeDispatch' => [
'callable' => 'beforeDispatch',
'priority' => 0
],
'Dispatcher.afterDispatch' => [
'callable' => 'afterDispatch',
'priority' => 99999
]
];
}
public function beforeDispatch(Event $event)
{
$request = $event->data['request'];
if ('OPTIONS' === $request->method()) {
$event->stopPropagation();
}
}
public function afterDispatch(Event $event)
{
$request = $event->data['request'];
$response = $event->data['response'];
$response->cors($request)
->allowOrigin('*')
->allowMethods(['GET', 'POST', 'OPTIONS'])
->allowHeaders(['Content-Type, Authorization, X-Requested-With, Accept'])
->allowCredentials()
->maxAge(0)
->build();
if ('OPTIONS' === $request->method()) {
$event->stopPropagation();
}
}
}
But the problem is, when I make an POST request to API endpoint from AngularJS, first it makes OPTIONS method call and then POST method. CakePHP does not process the OPTIONS method call and returns: 400 Bad Request
Below are the sample request and response headers:
Request headers
OPTIONS /v1/account/login HTTP/1.1
Host: api.cake.dev
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:48.0) Gecko/20100101 Firefox/48.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type
Origin: http://demo.angular.dev
Connection: keep-alive
Response headers
HTTP/1.1 400 Bad Request
Date: Wed, 07 Sep 2016 08:34:55 GMT
Server: Apache/2.4.17 (Win64) PHP/5.6.16
X-Powered-By: PHP/5.6.16
X-DEBUGKIT-ID: b4e5654a-cefb-43b7-bf19-4e8c7ffdb0e0
access-control-allow-origin: *
access-control-allow-methods: GET, POST, OPTIONS
access-control-allow-headers: Content-Type, Authorization, X-Requested-With, Accept
Access-Control-Allow-Credentials: true
access-control-max-age: 0
Content-Length: 147
Connection: close
Content-Type: text/html; charset=UTF-8
Is there a way available in CakePHP 3 to handle this OPTIONS request and return correct response so than the next POST request work correctly?
Please help. Thank you
With CakePHP 3.2+, I did in this way:
public function beforeRender(event $event) {
$this->setCorsHeaders();
}
public function beforeFilter(event $event) {
if ($this->request->is('options')) {
$this->setCorsHeaders();
return $this->response;
}
}
private function setCorsHeaders() {
$this->response = $this->response->cors($this->request)
->allowOrigin(['*'])
->allowMethods(['*'])
->allowHeaders(['x-xsrf-token', 'Origin', 'Content-Type', 'X-Auth-Token'])
->allowCredentials(['true'])
->exposeHeaders(['Link'])
->maxAge(300)
->build();
}
In this way, I can even handle CakePHP error pages.
Depending on your case, you can change values on allowHeaders array.
Remembering that if the request has withCredentials set to true, you will need to specify the origins.
if you guys really stuck on this then go to the config/bootstrap.php file and add the following line and your issue is gone
header('Access-Control-Allow-Origin: *');
For CakePHP 3.3+ version use this plugin : https://github.com/ozee31/cakephp-cors
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With