DistChen

跨域资源访问

当用 Ajax 跨域访问发布在 Tomcat 下的 web service时 ,会出现如下的错误。

XMLHttpRequest cannot load http://localhost:8081/DistServices/services/FolderService/GetAllFolderTypes. No ‘Access-Control-Allow-Origin’header is present on the requested resource. Origin ‘http://localhost:9206‘ istherefore not allowed access。

这个问题的产生是由于跨域访问时,request 来自的域(http://localhost:9206)不在服务(http://localhost:8081)所接受的域列表里面。说人话就是,哥的服务不是你想要就要得,没经过我的批准,你没法使用。就好像你去按摩店:"老板,来个漂亮妹子给我按摩。"。你想要这些服务,不给钱是不行的。

因此,要是想跨域访问这个服务,我们得经过服务发布者(老板)的允许,将我们发起请求的域加到服务器允许访问的域列表里面。问题知道了,那怎么做呢?

从上面的描述可以看出,工作主要在服务端,只要服务发布者允许,请求者就可以正常访问了,因此服务发布者需要做一些工作来达到这个目的。

CORS介绍

跨域资源共享(CORS )是一种网络浏览器的技术规范,它为Web服务器定义了一种方式,允许网页从不同的域访问其资源。而这种访问是被同源策略所禁止的。CORS系统定义了一种浏览器和服务器交互的方式来确定是否允许跨域请求。 。

简言之,CORS就是为了让AJAX可以实现可控的跨域访问而生的。

Tomcat下的配置

下载cors-filter-2.3.jar(其它版本也可),java-property-utils-1.9.jar这两个库文件,放到lib目录下。工程项目中web.xml中的配置如下:

加载 CORSFilter

1
2
3
4
5
6
7
<filter>
<filter-name>CORS</filter-name>
<filter-class>com.thetransactioncompany.cors.CORSFilter</filter-class>
</filter>

如果需要动态监测过滤规则的变化,那么应该使用如下的配置代替上面的配置(实际上就是使用另外一种类型的CORSFilter):

1
2
3
4
5
6
7
<filter>
<filter-name>CORS</filter-name>
<filter-class>com.thetransactioncompany.cors.autoreconf.AutoReconfigurableCORSFilter</filter-class>
</filter>

指定规则

如果只允许来自某个域(http://localhost:9206)的请求,那么给CORSFilter加如下参数:

1
2
3
4
5
6
7
<init-param>
<param-name>cors.allowOrigin</param-name>
<param-value>http://localhost:9206</param-value>
</init-param>

如果允许同时来自两个域(http://localhost:9206http://chenyp.com)的请求,那么给CORSFilter加如下参数:

1
2
3
4
5
6
7
<init-param>
<param-name>cors.allowOrigin</param-name>
<param-value>http://localhost:9206,http://chenyp.com</param-value>
</init-param>

如果允许来自任何域的请求,那么给CORSFilter加如下参数:

1
2
3
4
5
6
7
<init-param>
<param-name>cors.allowOrigin</param-name>
<param-value>*</param-value>
</init-param>

其它可配的参数还有:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<init-param>
<param-name>cors.supportedMethods</param-name>
<param-value>GET, POST, HEAD, PUT, DELETE</param-value>
</init-param>
<init-param>
<param-name>cors.supportedHeaders</param-name>
<param-value>Accept, Origin, X-Requested-With, Content-Type, Last-Modified</param-value>
</init-param>
<init-param>
<param-name>cors.exposedHeaders</param-name>
<param-value>Set-Cookie</param-value>
</init-param>
<init-param>
<param-name>cors.supportsCredentials</param-name>
<param-value>true</param-value>
</init-param>

如果不清楚这些参数所代表的意义,那么你可能需要了解下 HTTP请求报文。

指定需要过滤的请求

如果只对某个servlet 过滤,那么如下配置:

1
2
3
4
5
6
7
<filter-mapping>
<filter-name>CORS</filter-name>
<servlet-name>MyServlet</servlet-name>
</filter-mapping>

如果需要对所有的请求过滤,那么如下配置:

1
2
3
4
5
6
7
<filter-mapping>
<filter-name>CORS</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

这就是所有的配置了,一个完整的配置可能如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
<filter>
<filter-name>CORS</filter-name>
<filter-class>com.thetransactioncompany.cors.CORSFilter</filter-class>
<init-param>
<param-name>cors.allowOrigin</param-name>
<param-value>*</param-value>
</init-param>
<init-param>
<param-name>cors.supportedMethods</param-name>
<param-value>GET, POST, HEAD, PUT, DELETE</param-value>
</init-param>
<init-param>
<param-name>cors.supportedHeaders</param-name>
<param-value>Accept, Origin, X-Requested-With, Content-Type, Last-Modified</param-value>
</init-param>
<init-param>
<param-name>cors.exposedHeaders</param-name>
<param-value>Set-Cookie</param-value>
</init-param>
<init-param>
<param-name>cors.supportsCredentials</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CORS</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

除了这种类型的 CORSFilter ,Apache 也提供了用于同样目的的CORSFilter 类,原理和配置大同小异,有兴趣的可以看这里:http://tomcat.apache.org/tomcat-7.0-doc/config/filter.html#CORS_Filter

既然是一个Filter,那么我们自己也是可以编写对应的CORSFilter 类的,我在这里编写一个最简单的 CORSFilter:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
public class CORSFilter implements Filter {
private FilterConfig _CONFIG=null;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
_CONFIG=filterConfig;
}
@Override
public void doFilter(ServletRequest request,ServletResponse response,
FilterChain chain) throws IOException, ServletException {
if (_CONFIG!=null){
Enumeration names = _CONFIG.getInitParameterNames();
String name=null;
String value=null;
while (names.hasMoreElements()){
name=(String)names.nextElement();
value=_CONFIG.getInitParameter(name);
((HttpServletResponse)response).addHeader(name,value);
}
}
chain.doFilter(request,response);
}
@Override
public void destroy() {
_CONFIG=null;
}
}

对应的配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<filter>
<filter-name>CORSFilter</filter-name>
<filter-class>dist.filter.CORSFilter</filter-class>
<init-param>
<param-name>Access-Control-Allow-Origin</param-name>
<param-value>*</param-value>
</init-param>
<init-param>
<param-name>Access-Control-Allow-Headers</param-name>
<param-value>Origin, X-Requested-With, Content-Type, Accept</param-value>
</init-param>
<init-param>
<param-name>Access-Control-Allow-Methods</param-name>
<param-value>GET, POST, HEAD, PUT, DELETE</param-value>
</init-param>
<!-- 还可以继续配置其它参数 -->
</filter>
<filter-mapping>
<filter-name>CORSFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

不足之处,烦请指正!!

坚持原创技术分享,您的支持将鼓励我继续创作!