I'm using Restler to implement a simple REST API. Now if I need to consume that API via AJAX from another domain, I'm going to need to send a callback parameter along with my requests. Is there support for this in Restler (I have yet to find any real documentation)?
问题:
回答1:
For anyone coming to this page from googling, I submitted an issue at github, and got excellent support from the author. Turns out it's fairly trivial to implement, if you're familiar with how Restler is built.
From https://github.com/Luracast/Restler/issues/17
<?php
//jsonpformat.php
class JsonpFormat implements iFormat {
const MIME = 'text/javascript';
const EXTENSION = 'js';
/*
* JsonFormat is used internally
* @var JsonFormat;
*/
public $jsonFormat;
public static $functionName = 'parseResponse';
public function __construct() {
$this->jsonFormat = new JsonFormat ();
if (isset ( $_GET ['jsonp'] )) {
self::$functionName = $_GET ['jsonp'];
}
}
public function getMIMEMap() {
return array (self::EXTENSION => self::MIME );
}
public function getMIME() {
return self::MIME;
}
public function getExtension() {
return self::EXTENSION;
}
public function encode($data, $human_readable = FALSE) {
return self::$functionName . '(' . $this->jsonFormat->encode ( $data, $human_readable ) . ');';
}
public function decode($data) {
return $this->jsonFormat->decode ( $data );
}
public function setMIME($mime) {
//do nothing
}
public function setExtension($extension) {
//do nothing
}
}
?>
This should be saved in the same directory as the restler.php file. Once you have that, edit your gateway (index.php) to include this file and add it as a supported format. Example:
<?php
require_once '../../restler/restler.php';
#set autoloader
#do not use spl_autoload_register with out parameter
#it will disable the autoloading of formats
spl_autoload_register('spl_autoload');
$r = new Restler();
$r->setSupportedFormats('JsonpFormat','JsonFormat', 'XmlFormat');
$r->addAPIClass('BMI');
$r->handle();
?>
回答2:
This worked well for us: header('Access-Control-Allow-Origin: *');
Add this to a controller method prior to the return for a single end point, to the controller class constructor for all endpoints in that branch or higher up to allow it site wide.
If you are only allowing certain sites to access use header('Access-Control-Allow-Origin: example.com') or something like header('Access-Control-Allow-Origin: '. $remote_domain). Where $remote_domain is set dynamically based on some passed in token or such. Check out Cross-Origin Resource Sharing (CORS) for why to limit the use of * wildcard.
<?php
class Say {
__construct(){
header('Access-Control-Allow-Origin: *'); //Here for all /say
}
function hello($to='world') {
header('Access-Control-Allow-Origin: *'); //Here for just /say/hello
return "Hello $to!";
}
}
The above works for GET and POST, other actions require some additional header info from restler. Here are some examples:
header('Access-Control-Allow-Methods: GET, POST, DELETE, PUT, OPTIONS'); header('Access-Control-Allow-Headers: whatever_headers_you_allow, header1, header2');
For IE9 and below you will need to a JSONP hack. Restler has example of extending the iFormat class to wrap the API output JASONP style.
Check out Mozilla hacks for details on CORS. http://hacks.mozilla.org/2009/07/cross-site-xmlhttprequest-with-cors/ And check out OPTIONS in PHP REST API
回答3:
I'll add here that if for some reason you don't want to use JSONP, you can simply add:
header('Access-Control-Allow-Origin: *');
per punkael's first answer (he didn't specify where to do this in Rester). Add this line to restler.php in the sendData($data) function where Restler adds the header data to the response. This starts on line 378.
Take care however, as this will allow any domain to grab data from your API.