可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I\'m doing a ajax call to my own server on a platform which they set prevent these ajax calls (but I need it to fetch the data from my server to display retrieved data from my server\'s database).
My ajax script is working , it can send the data over to my server\'s php script to allow it to process.
However it cannot get the processed data back as it is blocked by \"Access-Control-Allow-Origin\"
I have no access to that platform\'s source/core. so I can\'t remove the script that it disallowing me to do so.
(P/S I used Google Chrome\'s Console and found out this error)
The Ajax code as shown below:
$.ajax({
type: \"GET\",
url: \"http://example.com/retrieve.php\",
data: \"id=\" + id + \"&url=\" + url,
dataType: \'json\',
cache: false,
success: function(data)
{
var friend = data[1];
var blog = data[2];
$(\'#user\').html(\"<b>Friends: </b>\"+friend+\"<b><br> Blogs: </b>\"+blog);
}
});
or is there a JSON
equivalent code to the ajax script above ? I think JSON
is allowed.
I hope someone could help me out.
回答1:
put it on top of retrieve.php
header(\'Access-Control-Allow-Origin: *\');
It is important to note that the header()
must be called before any actual output is sent.
Wrong
<html>
<?php
header(\'Access-Control-Allow-Origin: *\');
?>
Correct
<?php
header(\'Access-Control-Allow-Origin: *\');
?>
<html>
回答2:
Okay, but you all know that the * is a wildcard and allows cross site scripting from every domain?
You would like to send multiple Access-Control-Allow-Origin
headers for every site that\'s allowed to - but unfortunately its officially not supported to send multiple Access-Control-Allow-Origin
headers, or to put in multiple origins.
You can solve this by checking the origin, and sending back that one in the header, if it is allowed:
$origin = $_SERVER[\'HTTP_ORIGIN\'];
$allowed_domains = [
\'http://mysite1.com\',
\'https://www.mysite2.com\',
\'http://www.mysite2.com\',
];
if (in_array($origin, $allowed_domains)) {
header(\'Access-Control-Allow-Origin: \' . $origin);
}
Thats much safer. You might want to edit the matching and change it to a manual function with some regex, or something like that. At least this will only send back 1 header, and you will be sure its the one that the request came from. Please do note that all HTTP headers can be spoofed, but this header is for the client\'s protection. Don\'t protect your own data with those values. If you want to know more, read up a bit on CORS and CSRF.
Why is it safer?
Allowing access from other locations then your own trusted site allows for session highjacking. I\'m going to go with a little example - image Facebook allows a wildcard origin - this means that you can make your own website somewhere, and make it fire AJAX calls (or open iframes) to facebook. This means you can grab the logged in info of the facebook of a visitor of your website. Even worse - you can script POST
requests and post data on someone\'s facebook - just while they are browsing your website.
Be very cautious when using the ACAO
headers!
回答3:
Warning, Chrome (and other browsers) will complain that multiple ACAO headers are set if you follow some of the other answers.
The error will be something like XMLHttpRequest cannot load ____. The \'Access-Control-Allow-Origin\' header contains multiple values \'____, ____, ____\', but only one is allowed. Origin \'____\' is therefore not allowed access.
Try this:
$http_origin = $_SERVER[\'HTTP_ORIGIN\'];
$allowed_domains = array(
\'http://domain1.com\',
\'http://domain2.com\',
);
if (in_array($http_origin, $allowed_domains))
{
header(\"Access-Control-Allow-Origin: $http_origin\");
}
回答4:
I have fixed this problem when calling a MVC3 Controller.
I added:
Response.AddHeader(\"Access-Control-Allow-Origin\", \"*\");
before my
return Json(model, JsonRequestBehavior.AllowGet);
And also my $.ajax
was complaining that it does not accept Content-type header in my ajax call, so I commented it out as I know its JSON being passed to the Action.
Hope that helps.
回答5:
best would be to allow single domains, be careful about the http:// :
header(\'Access-Control-Allow-Origin: http://www.foo.com\', false);
header(\'Access-Control-Allow-Origin: http://www.foo2.com\', false));
回答6:
Have you tried actually adding the Access-Control-Allow-Origin header to the response sent from your server? Like, Access-Control-Allow-Origin: *
?
回答7:
It\'s a really bad idea to use *
, which leaves you wide open to cross site scripting. You basically want your own domain all of the time, scoped to your current SSL settings, and optionally additional domains. You also want them all to be sent as one header. The following will always authorize your own domain in the same SSL scope as the current page, and can optionally also include any number of additional domains. It will send them all as one header, and overwrite the previous one(s) if something else already sent them to avoid any chance of the browser grumbling about multiple access control headers being sent.
class CorsAccessControl
{
private $allowed = array();
/**
* Always adds your own domain with the current ssl settings.
*/
public function __construct()
{
// Add your own domain, with respect to the current SSL settings.
$this->allowed[] = \'http\'
. ( ( array_key_exists( \'HTTPS\', $_SERVER )
&& $_SERVER[\'HTTPS\']
&& strtolower( $_SERVER[\'HTTPS\'] ) !== \'off\' )
? \'s\'
: null )
. \'://\' . $_SERVER[\'HTTP_HOST\'];
}
/**
* Optionally add additional domains. Each is only added one time.
*/
public function add($domain)
{
if ( !in_array( $domain, $this->allowed )
{
$this->allowed[] = $domain;
}
/**
* Send \'em all as one header so no browsers grumble about it.
*/
public function send()
{
$domains = implode( \', \', $this->allowed );
header( \'Access-Control-Allow-Origin: \' . $domains, true ); // We want to send them all as one shot, so replace should be true here.
}
}
Usage:
$cors = new CorsAccessControl();
// If you are only authorizing your own domain:
$cors->send();
// If you are authorizing multiple domains:
foreach ($domains as $domain)
{
$cors->add($domain);
}
$cors->send();
You get the idea.