跨域即跨站HTTP请求(Cross-site HTTP request),指发起请求的资源所在域不同于请求指向资源所在域的HTTP请求。

1:jsonp原理

JSONP(JSON with Padding)是数据格式JSON的一种“使用模式”,可以让网页从别的网域要数据。jsonp 的原理很简单,利用了【前端请求静态资源的时候不存在跨域问题】这个思路,但是这个只支持get请求。既然这个方法叫 jsonp,后端数据一定要使用json 数据。

前端jquery的写法:

$.ajax({
type: "get",
url: baseUrl + "/jsonp/get",
dataType: "jsonp",
success: function(response) {
$("#response").val(JSON.stringify(response));
}
});

注意这里的ajax请求中,

dataType为jsonp类型,其他的和普通的请求没有区别。


在后端springMVC 中配置:

/**
 * 开启jsonp支持(只支持jackson),需要配置在springMVC中配置该bean
 */
@ControllerAdvice
public class JsonpAdvice extends AbstractJsonpResponseBodyAdvice {

    public JsonpAdvice(String... queryParamNames) {

        super(queryParamNames);
    }
}

在配置配置文件中配置:

<!--jsonp支持-->
    <bean class="com.cx.advice.JsonpAdvice">  //这里写的是文件的位置
        <constructor-arg index="0">
            <list>
                <value>callback</value>
            </list>
        </constructor-arg>
    </bean>



2:cors:

全称是"跨域资源共享"(Cross-origin resource sharing)。 它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。

前端jquery的写法:

$.ajax({
    type: "POST",
    url: baseUrl + "/jsonp/post",
    dataType: 'json',
    crossDomain: true,
    xhrFields: {
        withCredentials: true
    },
    data: {
        name: "name_from_frontend"
    },
    success: function (response) {
        console.log(response)// 返回的 json 数据
        $("#response").val(JSON.stringify(response));
    }
});

这里需要注意:

dataType: “json”,这里是 json,不是 jsonp,不是 jsonp,不是 jsonp。

crossDomain: true,这里代表使用跨域请求

xhrFields: {withCredentials: true},这样配置就可以把 cookie 带过去了,不然我们连 session 都没法维护,很多人都栽在这里。当然,如果你没有这个需求,也就不需要配置这个了。

后端springmvc的配置

spring MVC 从4.2版本开始增加了对CORS的支持

spring MVC 中增加CORS支持非常简单,可以配置全局的规则,也可以使用@CrossOrigin注解进行细粒度的配置。@CrossOrigin注解

对于大部分的 web 项目,一般都会有 mvc 相关的配置类,此类继承自 WebMvcConfigurerAdapter。如果你也使用 SpringMVC 4.2 以上的版本的话,直接像下面这样添加这个方法就可以了:


@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
 
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**/*").allowedOrigins("*");
    }
}

如果很不幸你的项目中 SpringMVC 版本低于 4.2,那么需要「曲线救国」一下:

这里进行一下补充:


Access-Control-Allow-Origin:| * // 授权的源控制
Access-Control-Max-Age:// 授权的时间
Access-Control-Allow-Credentials: true | false // 控制是否开启与Ajax的Cookie提交方式
Access-Control-Allow-Methods:[,]* // 允许请求的HTTP Method
Access-Control-Allow-Headers:[,]* // 控制哪些header能发送真正的请求
public class CrossDomainFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        response.addHeader("Access-Control-Allow-Origin", "*");// 如果提示 * 不行,请往下看
        response.addHeader("Access-Control-Allow-Credentials", "true");
        response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
        response.addHeader("Access-Control-Allow-Headers", "Content-Type");
        filterChain.doFilter(request, response);
    }
}


在 web.xml 中配置下 filter:

<filter>
    <filter-name>CrossDomainFilter</filter-name>
    <filter-class>com.javadoop.filters.CrossDomainFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>CrossDomainFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

如果读者发现浏览器提示不能用 ‘*’ 符号,那读者可以在上面的 filter 中根据 request 对象拿到请求头中的 referer(request.getHeader(“referer”)),然后动态地设置 “Access-Control-Allow-Origin”:

String referer = request.getHeader("referer");
if (StringUtils.isNotBlank(referer)) {
    URL url = new URL(referer);
    String origin = url.getProtocol() + "://" + url.getHost();
    response.addHeader("Access-Control-Allow-Origin", origin);
} else {
    response.addHeader("Access-Control-Allow-Origin", "*");
}

如果你使用Spring Boot,你可以通过这种方式方便的进行配置


@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/**")
            .allowedOrigins("http://domain2.com")
            .allowedMethods("PUT", "DELETE")
            .allowedHeaders("header1", "header2", "header3")
            .exposedHeaders("header1", "header2")
            .allowCredentials(false).maxAge(3600);
    }
}


不限制任何请求:

@Configuration
public class CorsConfig extends WebMvcConfigurerAdapter {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowedMethods("GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "TRACE");
    }
}

基于xml的配置:

<mvc:cors>
    <mvc:mapping path="/**" />
</mvc:cors>