我正在尝试允许访问我网站上的每个子域,以允许跨子域AJAX调用。有没有办法指定网站的所有子域,如*.example.com
,或者,当我列出多个域时,为什么以下内容不起作用:
header('Access-Control-Allow-Origin: http://api.example.com http://www.example.com');
我已经阅读了以下似乎相似的问题,如果不是与此问题相同,除了我想要访问子域这一事实,而且这个问题涉及一般域。
Access-Control-Allow-Origin Multiple Origin Domains?
如果上述问题是此问题的解决方案,那么我如何从标题中检索原点。似乎$ _SERVER ['HTTP_ORIGIN']非常不可靠,甚至不能跨浏览器。我需要能够在尝试使用javascript发送AJAX调用时在任何可能显示错误的浏览器中看到原点。
答案 0 :(得分:17)
此问题的解决方案是使用$ _SERVER ['HTTP_ORIGIN']变量来确定请求是否来自允许的域。然后它设置了这个:
header('Access-Control-Allow-Origin: '.$_SERVER['HTTP_ORIGIN']);
答案 1 :(得分:10)
这是我的表现。
Origin
标头由浏览器指定,并包含在其他域上请求脚本的域:
Origin: http://www.websiteA.com
因此,你可以"白名单"服务器端脚本中的多个域:
$allowedOrigins = [
"http://www.websiteA.com",
"https://www.websiteB.com"
// ... etc
];
您可以执行的操作是检查$_SERVER["HTTP_ORIGIN"]
全局是否包含该白名单中的域:
if (in_array($_SERVER["HTTP_ORIGIN"], $allowedOrigins)) {
并将Access-Control-Allow-Origin
响应标头设置为Origin
标头值为:
header("Access-Control-Allow-Origin: " . $_SERVER["HTTP_ORIGIN"]);
完整脚本:
$allowedOrigins = [
"http://www.websiteA.com",
"https://www.websiteB.com"
// ... etc
];
if (in_array($_SERVER["HTTP_ORIGIN"], $allowedOrigins)) {
header("Access-Control-Allow-Origin: " . $_SERVER["HTTP_ORIGIN"]);
}
答案 2 :(得分:3)
虽然答案有效,但它确实会破坏整个事物的目的,因为它允许来自任何主机的请求。
我用的是:
if(isset($_SERVER['HTTP_ORIGIN'])) {
$origin = $_SERVER['HTTP_ORIGIN'];
if($origin == 'https://sub1.my-website.com' OR $origin == 'https://sub2.my-website.com') {
header("Access-Control-Allow-Origin: $origin");
}
}
答案 3 :(得分:0)
我尝试使用这种方法来实现特定域的约束:
$allowed_origin = '';
$parts = explode('.', parse_url($_SERVER['HTTP_HOST'])['host']);
if(end($parts).".".prev($parts) === "com.domain") {
$allowed_origin = $_SERVER['HTTP_ORIGIN'];
header('Acesss-Control-Allow-Origin: '. $allowed_origin);
}
我希望它有效。
答案 4 :(得分:0)
如果您想要通配符域,我认为这会更有效
if(isset($_SERVER['HTTP_ORIGIN']) && preg_match('!^http(s)?://([a-z0-9\-]+\.)?example.com$!is', $_SERVER['HTTP_ORIGIN']))
{
header('Access-Control-Allow-Origin: '.$_SERVER['HTTP_ORIGIN']);
}
答案 5 :(得分:0)
//Function to be called first in php file.
function CORS_HEADERS_HANDLER(){
if (isset($_SERVER['HTTP_ORIGIN'])){
switch($_SERVER['HTTP_ORIGIN']){
//Handle an IP address and Port
case 'http://1.2.3.4:4200':
header('Access-Control-Allow-Origin: http://1.2.3.4:4200');
break;
//Handle an Website Domain (using https)
case 'https://www.someSite.com':
header('Access-Control-Allow-Origin: https://www.someSite.com');
break;
//Handle an Website Domain (using http)
case 'http://www.someSite.com':
header('Access-Control-Allow-Origin: http://www.someSite.com');
break;
//Catch if someone's site is actually the reject being cheeky
case 'https://not.you':
header('Access-Control-Allow-Origin: https://nice.try');
break;
//Handle a rejection passing something that is not the request origin.
default:
header('Access-Control-Allow-Origin: https://not.you');
break;
}
}else{
header('Access-Control-Allow-Origin: https://not.you');
}
header('Access-Control-Allow-Methods: GET, POST, PATCH, PUT, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: Origin, Content-Type, X-Auth-Token');
header('Access-Control-Allow-Credentials: true');
header('Content-Type: application/json; charset=utf-8');
header("Cache-Control: public,max-age=3600");
//if its an options request you don't need to proceed past CORS request.
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
die();
}
}
答案 6 :(得分:0)
这是我的挑战和解决方案:
1 - api.example.com 上的后端 PHP。
2 - 多个 JS 前端,例如 one.example.com、two.example.com 等
3 - Cookie 需要双向传递。
4 - api.example.com 上从多个前端到 PHP 后端的 AJAX 调用
5 - 在 PHP 中,我不喜欢使用 $_SERVER["HTTP_ORIGIN"],在我看来并不总是可靠/安全(我有一些浏览器的 HTTP-ORIGIN 总是空的)。
在具有单个前端域的 PHP 中执行此操作的正常方法是使用以下内容启动 PHP 代码:
header('Access-Control-Allow-Origin: https://one.example.com');
header('Access-Control-Allow-Headers: Origin, Content-Type, X-Auth-Token');
header('Access-Control-Allow-Credentials: true');
在 one.example.com 域上的 JS 中:
jQuery.ajax({
url: myURL,
type: "POST",
xhrFields: {withCredentials: true},
dataType: "text",
contentType: "text/xml; charset=\"utf-8\"",
cache: false,
headers: "",
data: myCallJSONStr,
success: function(myResponse) {.....}
但是,这是行不通的,因为我使用多个子域来调用我的 API 域。
并且此解决方案将不起作用,因为我想传递 cookie:
header('Access-Control-Allow-Origin: *');
与JS站点上的pass on cookie设置冲突:
xhrFields: {withCredentials: true}
这是我所做的:
1 - 使用 GET 参数传递子域。 2 - 在 PHP 中硬编码主域,因此只允许(所有)子域。
这是我的解决方案的 JS/JQuery AJAX 部分:
function getSubDomain(){
let mySubDomain = "";
let myDomain = window.location.host;
let myArrayParts = myDomain.split(".");
if (myArrayParts.length == 3){
mySubDomain = myArrayParts[0];
}
return mySubDomain;
}
在 AJAX 调用中:
let mySubDomain = getSubDomain();
if (mySubDomain != ""){
myURL += "?source=" + mySubDomain + "&end"; //use & instead of ? if URL already has GET parameters
}
jQuery.ajax({
url: myURL,
type: "POST",
xhrFields: {withCredentials: true},
dataType: "text",
contentType: "text/xml; charset=\"utf-8\"",
cache: false,
headers: "",
data: myCallJSONStr,
success: function(myResponse) {.....}
最后是 PHP 部分:
<?php
$myDomain = "example.com";
$mySubdomain = "";
if (isset($_GET["source"])) {
$mySubdomain = $_GET["source"].".";
}
$myDomainAllowOrigin = "https://".$mySubdomain.$myDomain;
$myAllowOrigin = "Access-Control-Allow-Origin: ".$myDomainAllowOrigin;
//echo $myAllowOrigin;
header($myAllowOrigin);
header('Access-Control-Allow-Headers: Origin, Content-Type, X-Auth-Token');
header('Access-Control-Allow-Credentials: true');
重要,不要忘记为所有子域设置 cookie,在这种情况下,cookie 的域将是:.example.com(因此在主域前面有一个点):
<?php
//////////////// GLOBALS /////////////////////////////////
$gCookieDomain = ".example.com";
$gCookieValidForDays = 90;
//////////////// COOKIE FUNTIONS /////////////////////////////////
function setAPCookie($myCookieName, $myCookieValue, $myHttponly){
global $gCookieDomain;
global $gCookieValidForDays;
$myExpires = time()+60*60*24*$gCookieValidForDays;
setcookie($myCookieName, $myCookieValue, $myExpires, "/", $gCookieDomain, true, $myHttponly);
return $myExpires;
}
此解决方案允许我从 example.com 上的任何子域调用 api.example.com 上的 API。
注意。对于只有一个调用子域的情况,我更喜欢使用 .htaccess 来设置 CORS 而不是 PHP。下面是一个 .htaccess (linux/apache) 的例子,只有 one.example.com 调用 api.example.com:
<IfModule mod_headers.c>
Header set Access-Control-Allow-Origin "https://one.example.com"
Header set Access-Control-Allow-Headers "Origin, Content-Type, X-Auth-Token"
Header set Access-Control-Allow-Credentials "true"
</IfModule>
并将这个 .htaccess 放在 api.example.com 的根目录中。
答案 7 :(得分:-3)
这是关于你的问题的好文章: http://hacks.mozilla.org/2009/07/cross-site-xmlhttprequest-with-cors/
如果这不够好或不起作用,你需要这样的代理: https://raw.github.com/cowboy/php-simple-proxy/master/ba-simple-proxy.php
然后您可以使用以下参数调用代理: http://www.example.com/ba-simple-proxy.php?url=https://api.example.com