在.htaccess中启用跨域资源共享(CORS)

94
我使用 SLIM PHP 框架创建了一个基础的 RESTful 服务,现在我正在尝试连接它,以便从 Angular.js 项目中访问该服务。 我已经阅读到 Angular 支持 CORS ,并且我只需要在我的 .htaccess 文件中添加这一行:Header set Access-Control-Allow-Origin "*"
我已经完成了这个步骤,我的 REST 应用程序仍然可以正常工作(没有因为错误的 .htaccess 文件而导致 500 内部服务器错误),但当我尝试从 test-cors.org 进行测试时,它会抛出错误。
Fired XHR event: loadstart
Fired XHR event: readystatechange
Fired XHR event: error

XHR status: 0
XHR status text: 
Fired XHR event: loadend

我的 .htaccess 文件看起来像这样

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ /index.php [QSA,L]
Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Methods: "GET,POST,OPTIONS,DELETE,PUT"

我需要在我的.htaccess文件中添加什么内容才能让CORS正常工作,还是有其他方法可以在我的服务器上启用CORS?

9个回答

112

既然我已经将所有内容都转发到index.php了,我想尝试在PHP中设置头部信息而不是在.htaccess文件中设置,结果成功了!太好了!以下是我添加到index.php的代码,供其他遇到这个问题的人参考。

// Allow from any origin
if (isset($_SERVER['HTTP_ORIGIN'])) {
    // should do a check here to match $_SERVER['HTTP_ORIGIN'] to a
    // whitelist of safe domains
    header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}");
    header('Access-Control-Allow-Credentials: true');
    header('Access-Control-Max-Age: 86400');    // cache for 1 day
}
// Access-Control headers are received during OPTIONS requests
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {

    if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD']))
        header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");         

    if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']))
        header("Access-Control-Allow-Headers: {$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']}");

}

感谢slashingweapon在这个问题上的回答。

因为我正在使用Slim框架,所以我添加了这条路由以使OPTIONS请求获得HTTP 200响应。

// return HTTP 200 for HTTP OPTIONS requests
$app->map('/:x+', function($x) {
    http_response_code(200);
})->via('OPTIONS');

2
到目前为止,您已经拯救了四条生命,尽管我只需要 header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}"); 。谢谢! - raph77777
2
经过查看其他答案,我对你的解决方案有一些担忧。作者slashingweapon包含了一个评论,你却将其删除,这促使你添加了一些逻辑来决定源是否是可信的。但是在这里,你盲目地将其删除,接受任何来源。这不是好的做法。 - Joe
1
@Joe 很好的观点。我更新了答案,并加上了一个关于检查来源的评论。 - Devin Crossman

105

应该使用add而不是set来编写.htaccess吗?

Header add Access-Control-Allow-Origin "*"
Header add Access-Control-Allow-Methods: "GET,POST,OPTIONS,DELETE,PUT"

1
谢谢!这解决了我的问题!我之前使用的是set,但它没用。改成add就可以了。值得一提的是,这是在一个WordPress博客上完成的,同时.htaccess文件中还有其他一些内容。 - BBog
1
这里的文档说“set” http://enable-cors.org/server_apache.html。可能引起了很多问题! - Ryan How
我从set改成了add,但仍然收到“预检请求返回的HTTP状态码400无效”的响应..请建议..我在这里描述了我的完整帖子: https://magento.stackexchange.com/questions/170342/magento-htaccess-response-for-preflight-has-invalid-http-status-code-400 - Sushivam
对我来说,第一行就足够了。另外,我猜第二行不应该有冒号? - kslstn
Apache文档中说的是“set”吗?https://httpd.apache.org/docs/2.4/mod/mod_headers.html - DrLightman
@kslstn 也可以使用冒号。 - Moritz Schmitz v. Hülst

38

以下是对我有效的方法:

Header add Access-Control-Allow-Origin "*"
Header add Access-Control-Allow-Headers "origin, x-requested-with, content-type"
Header add Access-Control-Allow-Methods "PUT, GET, POST, DELETE, OPTIONS"

16

就像这个回答Custom HTTP Header for a specific file中所述,你可以使用以下代码<File>来为单个文件启用CORS:

<Files "index.php">
  Header set Access-Control-Allow-Origin "*"
  Header set Access-Control-Allow-Methods: "GET,POST,OPTIONS,DELETE,PUT"
</Files>

你可以使用特定的起源(协议+域名+可选端口),而不是"*"


14

将会百分之百生效,应用于 .htaccess 文件:

# Enable cross domain access control
SetEnvIf Origin "^http(s)?://(.+\.)?(1xyz\.com|2xyz\.com)$" REQUEST_ORIGIN=$0
Header always set Access-Control-Allow-Origin %{REQUEST_ORIGIN}e env=REQUEST_ORIGIN
Header always set Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
Header always set Access-Control-Allow-Headers "x-test-header, Origin, X-Requested-With, Content-Type, Accept"

# Force to request 200 for options
RewriteEngine On
RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule .* / [R=200,L]

只想补充一点,有必要编辑SetEnvIf语句,定义哪些远程主机(1xyz.com、2xyz.com)允许CORS。 - user1298923

9

看起来你正在使用旧版本的slim(2.x)。你只需要在.htaccess文件中添加以下几行内容,无需对PHP脚本进行任何更改。

# Enable cross domain access control
SetEnvIf Origin "^http(s)?://(.+\.)?(domain_one\.com|domain_two\.net)$" REQUEST_ORIGIN=$0
Header always set Access-Control-Allow-Origin %{REQUEST_ORIGIN}e env=REQUEST_ORIGIN
Header always set Access-Control-Allow-Methods "GET, POST, PUT, DELETE"
Header always set Access-Control-Allow-Headers: Authorization

# Force to request 200 for options
RewriteEngine On
RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule .* / [R=200,L]

5
感谢Devin,我找到了解决我的SLIM应用程序多域访问问题的方法。
在htaccess中:
SetEnvIf Origin "http(s)?://(www\.)?(allowed.domain.one|allowed.domain.two)$" AccessControlAllowOrigin=$0$1
Header set Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
Header set Access-Control-Allow-Credentials true

在index.php文件中。
// Access-Control headers are received during OPTIONS requests
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {

    if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD']))
        header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");         

    if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']))
        header("Access-Control-Allow-Headers: {$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']}");
}
// instead of mapping:
$app->options('/(:x+)', function() use ($app) {
    //...return correct headers...
    $app->response->setStatus(200);
});

3

对于Ubuntu用户:

您需要使用以下命令先激活头文件模块:

sudo a2enmod headers

然后通过以下方式重启apache:

sudo service apache2 restart

然后在您的htaccess文件中添加以下标头:

Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Headers "origin, x-requested-with, content-type"
Header set Access-Control-Allow-Methods "PUT, GET, POST, DELETE, OPTIONS"

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接