是否有一种方法允许多个跨域使用Access-Control-Allow-Origin头?
我知道*,但它太开放了。我只讲几个域。
举个例子,是这样的:
Access-Control-Allow-Origin: http://domain1.example, http://domain2.example
我已经尝试了上面的代码,但它似乎不能在Firefox中工作。
是否可以指定多个域,还是只能指定一个域?
是否有一种方法允许多个跨域使用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;
}
}
其他回答
对于多个域,在你的。htaccess:
<IfModule mod_headers.c>
SetEnvIf Origin "http(s)?://(www\.)?(domain1.example|domain2.example)$" AccessControlAllowOrigin=$0$1
Header add Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
Header set Access-Control-Allow-Credentials true
</IfModule>
为了对. net应用程序进行相当简单的复制/粘贴,我写这个代码是从全局变量中启用CORS。asax文件。这段代码遵循当前接受的回答中给出的建议,将请求中给出的任何原点反映到响应中。这有效地实现了'*'而不使用它。
这样做的原因是它支持多种其他CORS功能,包括发送带有'withCredentials'属性设置为'true'的AJAX XMLHttpRequest的能力。
void Application_BeginRequest(object sender, EventArgs e)
{
if (Request.HttpMethod == "OPTIONS")
{
Response.AddHeader("Access-Control-Allow-Methods", "GET, POST");
Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
Response.AddHeader("Access-Control-Max-Age", "1728000");
Response.End();
}
else
{
Response.AddHeader("Access-Control-Allow-Credentials", "true");
if (Request.Headers["Origin"] != null)
Response.AddHeader("Access-Control-Allow-Origin" , Request.Headers["Origin"]);
else
Response.AddHeader("Access-Control-Allow-Origin" , "*");
}
}
听起来,推荐的方法是让服务器从客户端读取Origin头,将其与您希望允许的域列表进行比较,如果匹配,则将Origin头的值作为响应中的Access-Control-Allow-Origin头回显给客户端。
使用.htaccess,你可以这样做:
# ----------------------------------------------------------------------
# Allow loading of external fonts
# ----------------------------------------------------------------------
<FilesMatch "\.(ttf|otf|eot|woff|woff2)$">
<IfModule mod_headers.c>
SetEnvIf Origin "http(s)?://(www\.)?(google.com|staging.google.com|development.google.com|otherdomain.example|dev02.otherdomain.example)$" AccessControlAllowOrigin=$0
Header add Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
Header merge Vary Origin
</IfModule>
</FilesMatch>
为了方便ASMX服务的多域访问,我在全局中创建了这个函数。asax文件:
protected void Application_BeginRequest(object sender, EventArgs e)
{
string CORSServices = "/account.asmx|/account2.asmx";
if (CORSServices.IndexOf(HttpContext.Current.Request.Url.AbsolutePath) > -1)
{
string allowedDomains = "http://xxx.yyy.example|http://aaa.bbb.example";
if(allowedDomains.IndexOf(HttpContext.Current.Request.Headers["Origin"]) > -1)
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", HttpContext.Current.Request.Headers["Origin"]);
if(HttpContext.Current.Request.HttpMethod == "OPTIONS")
HttpContext.Current.Response.End();
}
}
这也允许CORS处理OPTIONS动词。
如上所述,Access-Control-Allow-Origin应该是唯一的,如果您位于CDN(内容分发网络)后面,则应该将Vary设置为Origin。
Nginx配置的相关部分:
if ($http_origin ~* (https?://.*\.mydomain\.com(:[0-9]+)?)) {
set $cors "true";
}
if ($http_origin ~* (https?://.*\.my-other-domain\.com(:[0-9]+)?)) {
set $cors "true";
}
if ($cors = "true") {
add_header 'Access-Control-Allow-Origin' "$http_origin";
add_header 'X-Frame-Options' "ALLOW FROM $http_origin";
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Vary' 'Origin';
}