Silex CORS solution for OPTIONS requests
Recently, I have worked on a cross platform app that needed a php back end.
I elected to build the back end api upon Silex framework. The back end and front end applications were served over two subdomains. The issue here is that the requesting application is making Cross Origin requests to the back end and OPTIONS requests were needed to see whether it can make the actual request and by default Silex doesn’t have a default handler for OPTIONS requests.
To fix this, an OPTIONS route needed to be created for each of the application routes. Many providers solve this by looping through each route defined in your app and creating a corresponding OPTIONS route. Even for small apps, however, this is adding unnecessary processing and for large apps with lots of routes it is even slower.
To get around this, I’ve added two bits of code to my application. The first in bootstrap/app file.
$app->after(function (Request $request, Response $response) {
$response->headers->set('Access-Control-Allow-Origin', '*');
$response->headers->set('Access-Control-Allow-Headers', 'Authorization');
});
What this does is add two headers to all responses after the controller has finished executing but before the response is returned. Here we’ve added the Access-Control-Allow-Origin
header the javascript app is looking for. I’m also telling the app that sending an Authorization
header is fine too. You can remove that line if you don’t need it.
We still have an issue though, all of the GET
and POST
requests defined in the routes will have the correct headers, but Silex still doesn’t know what to do with the OPTIONS
requests. Fixing that is as easy as adding the following snippet to your routes files.
$app->options("{path}", function () {
return new \Symfony\Component\HttpFoundation\JsonResponse(null, 204);
})->assert("path", ".*");
All we’re doing here is matching against any OPTIONS
requests and returning a 204
response with no content. The code we added earlier will still apply to this response so our headers are correct. If needed, you can check inside the function to see whether the URL matches a URL in your non OPTIONS
routes.