前言

当Web项目中使用API与第三方对接时,从一台服务器尝试访问另一台服务器时通过XMLHttpRequest或者fetch发起的跨域请求在浏览器中是会被拦截的,并会在控制台提示

Access to fetch at 'http://192.168.1.23:8088/user/add' from origin http://192.168.1.24' has been blocked by CORS policy...

其中CORS全称"跨域资源共享"(Cross-origin resource sharing),是用来避免浏览器的同源策略拦截跨域请求的问题的。

CORS通过先发送一个OPTIONS类型的HTTP请求到服务器,检查当前发起请求的源是否在服务器中是被认可的跨域请求发起站点,如果是,则在该请求的Response中返回允许该请求访问的头信息,此时浏览器会再次发起正式的数据请求。

通过在服务器中开启CORS支持,则可方便地进行跨域调用了。

Tomcat配置

在Tomcat7中服务器已经支持了CORS请求,只需要我们在 web.xml 中开启支持即可。

catalina.bat version

#Server version: Apache Tomcat/7.0.56
#Server built:   Sep 26 2014 12:08:24
#......

通过在tomcat的bin目录下运行以上命令则可查看Tomcat的版本

<!-- <?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
	http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> -->
<web-app
        xmlns="http://java.sun.com/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
        version="3.0"
        metadata-complete="false"
        >
	<welcome-file-list>
		<welcome-file>login.jsp</welcome-file>
	</welcome-file-list>
	
	<filter>
	  <filter-name>CorsFilter</filter-name>
	  <filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
	  <init-param>
		<param-name>cors.allowed.origins</param-name>
		<param-value>*</param-value>
	  </init-param>
	  <init-param>
		<param-name>cors.allowed.methods</param-name>
		<param-value>POST,GET,DELETE,OPTIONS,PUT</param-value>
	  </init-param>
	</filter>
	<filter-mapping>
	  <filter-name>CorsFilter</filter-name>
	  <url-pattern>/*</url-pattern>
	</filter-mapping>

<!--  ......  -->

在web.xml文件中加入 <filter> 标签并使用默认的CORS实现,需要将该过滤器配置在首位。

其中cors.allowed.origins表示允许跨域请求的来源,如果仅限特定IP访问则只需要填写对应的IP即可。

其中cors.allowed.methods表示可以通过CORS使用的方法,此处配置上在RESTful服务中使用得较广泛的请求。

<url-pattern> 中的 /* 表示拦截所有的请求。

浏览器测试

XMLHTTPRequest 测试

在我们自己的服务页面打开浏览器的开发者控制台,使用下面的例子进行测试

var data =  {"userId": "1234567"};
var url = '192.168.1.23:8088/user/add';
var xhr = new XMLHttpRequest();
xhr.open('POST', url, true);
xhr.setRequestHeader('Content-type', 'application/json'); //(1)
xhr.send(JSON.stringify(data));

fetch 测试

var data =  {"userId": "1234567"};
var headers = {
		Accept: 'application/json',
		Content-Type: 'application/json' //(1)
	      };
var url = '192.168.1.23:8088/user/add';
fetch(url, {
	method: 'POST',
	headers: headers,
	body: JSON.stringify(data)
	});

上述测试用例中的 (1) 这一行不可省略,如果不写则CORS过滤器会将该请求认定为无效请求导致跨域请求失败。

后记

如果需要使用对HTTPS的服务器进行跨域请求,则需要HTTPS服务器需要有可信的SSL证书才能请求成功,否则在提示连接未授权从而无法发起跨域请求。