我们现在开发的应用一般都会将前台和后台进行数据传输,或者是我们的应用服务器需要提供数据给多个应用使用的时候,要注意的是跨域是浏览器设置的一个安全策略,也就是说,要是我们的服务不是提供给浏览器使用的,就不需要考虑跨域的问题,当然要是我们进行的是web应用的开发的话,就要关注跨域的问题了
浏览器对不同域名的请求的处理是,先发送一个options的请求,该请求只是单纯的将服务器的响应头和我们的请求头进行比较,如果响应头里面设置了允许跨域的话,就发送真正的数据请求过去
servlet容器中对于options的请求默认是不会分发的我们的业务控制器层的,所以我们可以有两种方式来实现对于跨域请求的处理
- ###### 使用filter
filter是web容器层,也就是servlet容器对请求进行过滤,所以我们可以使用filter在servlet容器对options请求进行处理之前自己进行一番处理,首先我们需要实现servlet的filter接口,然后在里面对请求进行处理,如:
package uc.meven.test2.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Component
public class MyCORSFilter implements Filter{
private static final Logger log = LoggerFactory.getLogger(MyCORSFilter.class);
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) servletResponse;
// String origin = (String) servletRequest.getRemoteHost()+":"+servletRequest.getRemotePort();
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with,Authorization,x-csrf-token");
response.setHeader("Access-Control-Allow-Credentials","true");
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void init(FilterConfig arg0) throws ServletException {
// TODO Auto-generated method stub
}
}
然后在web容器中加上我们自定义的过滤器,也就是在web.xml中
<filter>
<filter-name>cors</filter-name>
<!--定义的filter类的位置-->
<filter-class>uc.meven.test2.filter.MyCORSFilter</filter-class>
</filter>
<filter-mapping>
<!--只过滤一部分请求,/ajax下的全部请求都可以跨域-->
<filter-name>cors</filter-name>
<url-pattern>/ajax/*</url-pattern>
</filter-mapping>
- ###### 另外我们也可以不在servlet容器层对跨域请求进行处理,可以上浮到我们的spring层,这时我们需要将servlet对于options请求不进行分发的配置给开起来,在web.xml中加入
<init-param>
<param-name>dispatchOptionsRequest</param-name>
<param-value>true</param-value>
</init-param>
然后我们可以加入一个interceptor的请求拦截器,对所有的请求进行拦截,设置允许跨域,这时我们需要实现spring的HandlerInterceptor拦截器接口,对options请求进行处理
package uc.meven.test2.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
public class AccessControllerInterceptor implements HandlerInterceptor {
private static final Logger log = LoggerFactory.getLogger(AccessControllerInterceptor.class);
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
log.info("enter interceptor===========");
// TODO Auto-generated method stub
final String uri = request.getRequestURI();
final String origin = request.getHeader(HttpHeaders.ORIGIN);
response.setHeader("Access-Control-Allow-Origin", origin);
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, accept, apikey, sign, timestamp");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
log.info("request uri:{}, origin:{}, access success", uri, origin);
// 如果是options请求的话,直接返回,不是的话到业务层进行处理
return !"options".equalsIgnoreCase(request.getMethod());
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
// TODO Auto-generated method stub
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
// TODO Auto-generated method stub
}
}
接下来我们需要在springmvc的配置中启用我们的interceptor
<mvc:interceptors>
<bean class="uc.meven.test2.interceptor.AccessControllerInterceptor" />
</mvc:interceptors>
虽然我们可以使用第二中方式来实现跨越请求的处理,但是按照软件分层的概念,我们应该再servlet容器层进行这方面的处理,不污染我们的业务层代码,所以推荐使用第一种方式