是否有一种方法允许多个跨域使用Access-Control-Allow-Origin头?

我知道*,但它太开放了。我只讲几个域。

举个例子,是这样的:

Access-Control-Allow-Origin: http://domain1.example, http://domain2.example

我已经尝试了上面的代码,但它似乎不能在Firefox中工作。

是否可以指定多个域,还是只能指定一个域?


当前回答

下面是一个Java web应用的解决方案,基于yesthatguy的回答。

我使用的是Jersey REST 1.x

配置web.xml以识别Jersey REST和CORSResponseFilter

<!-- Jersey REST config -->
<servlet>
  <servlet-name>JAX-RS Servlet</servlet-name>
  <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
  <init-param>
    <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
    <param-value>true</param-value>
  </init-param>
  <init-param>
    <param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>
    <param-value>com.your.package.CORSResponseFilter</param-value>
  </init-param>
  <init-param>
    <param-name>com.sun.jersey.config.property.packages</param-name>
    <param-value>com.your.package</param-value>
  </init-param>
  <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
  <servlet-name>JAX-RS Servlet</servlet-name>
  <url-pattern>/ws/*</url-pattern>
</servlet-mapping>

下面是CORSResponseFilter的代码

import com.sun.jersey.spi.container.ContainerRequest;
import com.sun.jersey.spi.container.ContainerResponse;
import com.sun.jersey.spi.container.ContainerResponseFilter;


public class CORSResponseFilter implements ContainerResponseFilter{

    @Override
    public ContainerResponse filter(ContainerRequest request,
            ContainerResponse response) {
        
        String[] allowDomain = {"http://localhost:9000","https://my.domain.example"};
        Set<String> allowedOrigins = new HashSet<String>(Arrays.asList (allowDomain));                  
        
        String originHeader = request.getHeaderValue("Origin");
        
        if(allowedOrigins.contains(originHeader)) {
            response.getHttpHeaders().add("Access-Control-Allow-Origin", originHeader);
                        
            response.getHttpHeaders().add("Access-Control-Allow-Headers",
                    "origin, content-type, accept, authorization");
            response.getHttpHeaders().add("Access-Control-Allow-Credentials", "true");
            response.getHttpHeaders().add("Access-Control-Allow-Methods",
                    "GET, POST, PUT, DELETE, OPTIONS, HEAD");
        }
        
        return response;
    }
}

其他回答

我有同样的问题与woff字体,多子域必须有访问。为了允许子域,我在我的httpd.conf中添加了这样的东西:

SetEnvIf Origin "^(.*\.example\.com)$" ORIGIN_SUB_DOMAIN=$1
<FilesMatch "\.woff$">
    Header set Access-Control-Allow-Origin "%{ORIGIN_SUB_DOMAIN}e" env=ORIGIN_SUB_DOMAIN
</FilesMatch>

对于多个域,您可以更改SetEnvIf中的正则表达式。

匹配子域的PHP代码示例。

if( preg_match("/http:\/\/(.*?)\.yourdomain.example/", $_SERVER['HTTP_ORIGIN'], $matches )) {
        $theMatch = $matches[0];
        header('Access-Control-Allow-Origin: ' . $theMatch);
}

下面是apache的扩展选项,包括一些最新的和计划中的字体定义:

<FilesMatch "\.(ttf|otf|eot|woff|woff2|sfnt|svg)$">
    <IfModule mod_headers.c>
        SetEnvIf Origin "^http(s)?://(.+\.)?(domainname1|domainname2|domainname3)\.(?:com|net|org)$" AccessControlAllowOrigin=$0$1$2
        Header add Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
        Header set Access-Control-Allow-Credentials true
    </IfModule>
</FilesMatch>

我在PHP中使用的另一个解决方案:

$http_origin = $_SERVER['HTTP_ORIGIN'];

if ($http_origin == "http://www.domain1.com" || $http_origin == "http://www.domain2.com" || $http_origin == "http://www.domain3.com")
{  
    header("Access-Control-Allow-Origin: $http_origin");
}

Nginx用户允许多个域的CORS。我喜欢@marshall的例子,尽管他的回答只匹配一个域。为了匹配域和子域的列表,这个正则表达式可以很容易地使用字体:

location ~* \.(?:ttf|ttc|otf|eot|woff|woff2)$ {
   if ( $http_origin ~* (https?://(.+\.)?(domain1|domain2|domain3)\.(?:me|co|com)$) ) {
      add_header "Access-Control-Allow-Origin" "$http_origin";
   }
}

这将只回显与给定域列表匹配的“Access-Control-Allow-Origin”标头。