我们现在开发的应用一般都会将前台和后台进行数据传输,或者是我们的应用服务器需要提供数据给多个应用使用的时候,要注意的是跨域是浏览器设置的一个安全策略,也就是说,要是我们的服务不是提供给浏览器使用的,就不需要考虑跨域的问题,当然要是我们进行的是web应用的开发的话,就要关注跨域的问题了

浏览器对不同域名的请求的处理是,先发送一个options的请求,该请求只是单纯的将服务器的响应头和我们的请求头进行比较,如果响应头里面设置了允许跨域的话,就发送真正的数据请求过去

servlet容器中对于options的请求默认是不会分发的我们的业务控制器层的,所以我们可以有两种方式来实现对于跨域请求的处理

  1. ###### 使用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>
  1. ###### 另外我们也可以不在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容器层进行这方面的处理,不污染我们的业务层代码,所以推荐使用第一种方式