我正在尝试为所有子域,端口和协议启用CORS。
例如,我希望能够从http://sub.mywebsite.example:8080/到https://www.mywebsite.example/*运行XHR请求
通常情况下,我想启用来自源匹配的请求(并且仅限于):
/ / * .mywebsite.example: * / *
我正在尝试为所有子域,端口和协议启用CORS。
例如,我希望能够从http://sub.mywebsite.example:8080/到https://www.mywebsite.example/*运行XHR请求
通常情况下,我想启用来自源匹配的请求(并且仅限于):
/ / * .mywebsite.example: * / *
当前回答
根据daverrandom的回答,我也在玩,找到了一个稍微简单一点的Apache解决方案,它产生了相同的结果(Access-Control-Allow-Origin被动态地设置为当前特定的协议+域+端口),而不使用任何重写规则:
SetEnvIf Origin ^(https?://.+\.mywebsite\.example(?::\d{1,5})?)$ CORS_ALLOW_ORIGIN=$1
Header append Access-Control-Allow-Origin %{CORS_ALLOW_ORIGIN}e env=CORS_ALLOW_ORIGIN
Header merge Vary "Origin"
就是这样。
那些想要在父域(例如mywebsite.example)以及所有子域上启用CORS的人可以简单地将第一行中的正则表达式替换为:
^ (https ?://(?:.+\.)? mywebsite \ .example (?:: \ d{1, 5}) ?)美元。
注意:为了符合规范和正确的缓存行为,ALWAYS为启用cors的资源添加Vary: Origin响应头,即使对于非cors请求和来自不允许的源的请求也是如此(参见示例原因)。
其他回答
对于Spring,你应该使用allowedOriginPatterns,它完全是你想要的
setAllowedOrigins(java.util.List<java.lang.String>)的替代方案,除了端口列表外,还支持在主机名中的任何位置使用“*”的更灵活的起源模式。例子:
https://*.domain1.com -- domains ending with domain1.com
https://*.domain1.com:[8080,8081] -- domains ending with domain1.com on port 8080 or port 8081
https://*.domain1.com:[*] -- domains ending with domain1.com on any port, including the default port
与只支持""而不能与allowCredentials一起使用的allowedOrigins相反,当一个allowedOriginPattern被匹配时,Access-Control-Allow-Origin响应头被设置为匹配的原点,而不是""或模式。因此,allowedOriginPatterns可以与setAllowCredentials(java.lang.Boolean)设置为true结合使用。
例如:
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
List<String> allowedOrigins = List.of("https://*.example.com", "http://*.example2.com[80,8080]");
registry.addMapping("/**").allowedOriginPatterns(allowedOrigins.toArray(new String[0]));
}
};
}
我不得不稍微修改Lars的回答,因为正则表达式中出现了一个孤立的\,只比较实际的主机(不注意协议或端口),我想在我的生产域之外支持localhost域。因此,我将$allowed参数更改为一个数组。
function getCORSHeaderOrigin($allowed, $input)
{
if ($allowed == '*') {
return '*';
}
if (!is_array($allowed)) {
$allowed = array($allowed);
}
foreach ($allowed as &$value) {
$value = preg_quote($value, '/');
if (($wildcardPos = strpos($value, '\*')) !== false) {
$value = str_replace('\*', '(.*)', $value);
}
}
$regexp = '/^(' . implode('|', $allowed) . ')$/';
$inputHost = parse_url($input, PHP_URL_HOST);
if ($inputHost === null || !preg_match($regexp, $inputHost, $matches)) {
return 'none';
}
return $input;
}
用法如下:
if (isset($_SERVER['HTTP_ORIGIN'])) {
header("Access-Control-Allow-Origin: " . getCORSHeaderOrigin(array("*.myproduction.com", "localhost"), $_SERVER['HTTP_ORIGIN']));
}
我在回答这个问题,因为公认的答案做不到跟随
正则表达式分组会影响性能,但这是不必要的。 不能匹配主域,只适用于子域。
例如:它不会为http://mywebsite.example发送CORS头,而为http://somedomain.mywebsite.example/工作
SetEnvIf Origin "http(s)?://(.+\.)?mywebsite\.com(:\d{1,5})?$" CORS=$0
Header set Access-Control-Allow-Origin "%{CORS}e" env=CORS
Header merge Vary "Origin"
要启用你的网站,你只是把你的网站在mywebsite的地方。在上面的Apache配置的例子。
允许多个站点:
SetEnvIf Origin "http(s)?://(.+\.)?(othersite\.com|mywebsite\.example)(:\d{1,5})?$" CORS=$0
部署后验证:
下面的curl响应在更改后应该具有“Access-Control-Allow-Origin”标头。
curl -X GET -H "Origin: http://site1.example" --verbose http://site2.example/query
根据daverrandom的回答,我也在玩,找到了一个稍微简单一点的Apache解决方案,它产生了相同的结果(Access-Control-Allow-Origin被动态地设置为当前特定的协议+域+端口),而不使用任何重写规则:
SetEnvIf Origin ^(https?://.+\.mywebsite\.example(?::\d{1,5})?)$ CORS_ALLOW_ORIGIN=$1
Header append Access-Control-Allow-Origin %{CORS_ALLOW_ORIGIN}e env=CORS_ALLOW_ORIGIN
Header merge Vary "Origin"
就是这样。
那些想要在父域(例如mywebsite.example)以及所有子域上启用CORS的人可以简单地将第一行中的正则表达式替换为:
^ (https ?://(?:.+\.)? mywebsite \ .example (?:: \ d{1, 5}) ?)美元。
注意:为了符合规范和正确的缓存行为,ALWAYS为启用cors的资源添加Vary: Origin响应头,即使对于非cors请求和来自不允许的源的请求也是如此(参见示例原因)。
使用@Noyo的解决方案,而不是这个。它更简单、更清晰,而且可能在负载下性能更高。
原来的答案只用于历史目的!!
我在这个问题上做了一些尝试,并提出了这个可重用的.htaccess(或httpd.conf)解决方案,适用于Apache:
<IfModule mod_rewrite.c>
<IfModule mod_headers.c>
# Define the root domain that is allowed
SetEnvIf Origin .+ ACCESS_CONTROL_ROOT=yourdomain.example
# Check that the Origin: matches the defined root domain and capture it in
# an environment var if it does
RewriteEngine On
RewriteCond %{ENV:ACCESS_CONTROL_ROOT} !=""
RewriteCond %{ENV:ACCESS_CONTROL_ORIGIN} =""
RewriteCond %{ENV:ACCESS_CONTROL_ROOT}&%{HTTP:Origin} ^([^&]+)&(https?://(?:.+?\.)?\1(?::\d{1,5})?)$
RewriteRule .* - [E=ACCESS_CONTROL_ORIGIN:%2]
# Set the response header to the captured value if there was a match
Header set Access-Control-Allow-Origin %{ACCESS_CONTROL_ORIGIN}e env=ACCESS_CONTROL_ORIGIN
</IfModule>
</IfModule>
只要将块顶部的ACCESS_CONTROL_ROOT变量设置为您的根域,它将在Access-Control-Allow-Origin: response头值中将Origin: request头值回显给客户端,如果它与您的域匹配。
还请注意,您可以使用sub.mydomain.example作为ACCESS_CONTROL_ROOT,它将限制源为sub.mydomain.example和*.sub.mydomain。示例(即它不必是域根)。可以通过修改正则表达式的URI匹配部分来控制允许变化的元素(协议、端口)。