Solved thread

This post is marked as solved. If you think the information contained on this thread must be part of the official documentation, please contribute submitting a pull request to its repository.

Enable Cross Origin Resource Sharing

Hello, I'm developing a RESTful API and I need to enable my API to accept request from different domain. So, I need to enable Cross Origin Resource Sharing. Anybody know how can I do that?

Thanks



4.8k
Accepted
answer
edited Jul '14

Hi, I found the solution.

First you need to define some headers to your method:

$response = $app->response;                      
$response->setHeader('Access-Control-Allow-Origin', '*');
$response->setHeader('Access-Control-Allow-Headers', 'X-Requested-With');      
$response->sendHeaders();

And you need to create a method to preflight. Like that:

$app->get('/preflight', function() use ($app) {
        $content_type = 'application/json';
        $status = 200;
        $description = 'OK';
        $response = $app->response;

        $status_header = 'HTTP/1.1 ' . $status . ' ' . $description;
        $response->setRawHeader($status_header);
        $response->setStatusCode($status, $description);
        $response->setContentType($content_type, 'UTF-8');
        $response->setHeader('Access-Control-Allow-Origin', '*');
        $response->setHeader('Access-Control-Allow-Headers', 'X-Requested-With');
        $response->setHeader("Access-Control-Allow-Headers: Authorization");
        $response->setHeader('Content-type: ' . $content_type);
        $response->sendHeaders();
    });

Good to know! - I started googling around for this info but am glad you found it! :)

I have a basic API project that handles this: https://github.com/cmoore4/phalcon-rest

Check out controllers/RESTController.php. See the optionsBase and optionsOne functions.

Then all you need to do is define a route: $app->options('/', 'optionsBase'); See the index.php file for examples.

Preflight is handled via OPTIONS in most browsers.



85
edited Jul '14

Hi guys, here is how to handle it:

$app->before(function() use ($app) {
$origin = $app->request->getHeader("ORIGIN") ? $app->request->getHeader("ORIGIN") : '*';

$app->response->setHeader("Access-Control-Allow-Origin", $origin)
      ->setHeader("Access-Control-Allow-Methods", 'GET,PUT,POST,DELETE,OPTIONS')
      ->setHeader("Access-Control-Allow-Headers", 'Origin, X-Requested-With, Content-Range, Content-Disposition, Content-Type, Authorization')
      ->setHeader("Access-Control-Allow-Credentials", true);
});

$app->options('/{catch:(.*)}', function() use ($app) { 
    $app->response->setStatusCode(200, "OK")->send();
});

The ->before() block is required if your API is consummed by client-side JS (Angular, EmberJS...) and is executed ONLY if a route has been matched, that's why you need the ->options() catch-all block.

@Pierre your method works only with Phalcon\Mvc\Micro because Phalcon\Mvc\Application class doesn't have options() and before() methods.



85

I didn't implement this on the full-stack framework yet, I can't help you more.

I don't need help, it was just a precisation.



127

Just in case it results useful for someone else I publish here my plugin:

use Phalcon\Events\Event;
use Phalcon\Mvc\Micro;
use Phalcon\Mvc\User\Plugin;

class CORSPlugin extends Plugin {

    public function beforeHandleRoute(Event $event, Micro $app) {
        $origin = $app->request->getHeader('ORIGIN') ? $app->request->getHeader('ORIGIN') : '*';

        if (strtoupper($app->request->getMethod()) == 'OPTIONS') {
            $app->response
                ->setHeader('Access-Control-Allow-Origin', $origin)
                ->setHeader('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS')
                ->setHeader('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Range, Content-Disposition, Content-Type, Authorization')
                ->setHeader('Access-Control-Allow-Credentials', 'true');

            $app->response->setStatusCode(200, 'OK')->send();

            exit;
        }

        $app->response
            ->setHeader('Access-Control-Allow-Origin', $origin)
            ->setHeader('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS')
            ->setHeader('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Range, Content-Disposition, Content-Type, Authorization')
            ->setHeader('Access-Control-Allow-Credentials', 'true');
    }

}

Then when defining the Micro app:

$di->set('cors', function() {
    return new CORSPlugin;
}, true);

$em = new EventsManager;
$em->attach('micro:beforeHandleRoute', $di->get('cors'));

$app = new Micro($di);
$app->setEventsManager($em);
edited Feb '17

Edited: It was the Access-Control-Allow-Origin that was wrong. Sorry

Hi all,

I using the @Pierre solution. It works well, but after the 200 OK response to the options my app does not manage the POST. Any clue?