解决跨域请求问题

背景

浏览器的同源策略与跨域 两个页面地址中的协议、域名和端口号一致,则表示同源。

同源策略的限制:

  • 存储在浏览器中的数据,如localStroage、Cooke和IndexedDB不能通过脚本跨域访问

  • 不能通过脚本操作不同域下的DOM

  • 不能通过ajax请求不同域的数据

何为ajax请求 AJAX只是一种技术,不是某种具体的东西。不同的浏览器有自己实现AJAX的组件。 AJAX 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。 用了AJAX之后,你点击,然后页面上的一行字就变化了,页面本身不用刷。

服务器端通过在响应的 header 中设置 Access-Control-Allow-Origin 及相关一系列参数,提供跨域访问的允许策略。

```java 示例 //允许所有 response.setHeader("Access-Control-Allow-Origin", "*"); //允许特定 if(request.getHeader("Origin").contains("mydomain.com")) { response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin")); }

### spring boot 通过配置文件实现

```java
/**
* 跨域请求配置
* 可以单独作为一个配置文件类,也可以直接放在spring boot的启动类中
*/
@Configuration
public class CorsConfig {
    private CorsConfiguration buildConfig() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOrigin("*");
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");
        //允许跨域携带cookie
        corsConfiguration.setAllowCredentials(true);
        return corsConfiguration;
    }

    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", buildConfig());
        return new CorsFilter(source);
    }
}

如果这些GET或POST请求不需要传递Cookie数据的话,就没什么问题了,但如果需要,那么会发现 虽然已经处理了跨域请求的问题,但后台始终无法获取到Cookie。跨域传输Cookie是需要后台和前台同时做相关处理才能解决的。

前端代码 angularjs配置方法

```javascript angularjs //单独配置 $http.post("http://a.domain.com/Api/Product", { productId: 3 }, { withCredentials: true, params: { name: "Ray" } }).success(function (data) { //TODO }); //全局配置 angular.module("app").config(function ($httpProvider) { $httpProvider.defaults.withCredentials = true; })

jquery配置方法

```javascript jquery
$.ajax({
    type: "POST",
    url: "http://a.domain.com/Api/Product",
    xhrFields: {
        withCredentials: true
    },
    success: function (data) {
        console.log(data)
    },
    error: function (data) {
        console.error(data)
    }
})

后端代码 对应客户端的 xhrFields.withCredentials: true 参数,服务器端通过在响应 header 中设置 Access-Control-Allow-Credentials = true 来运行客户端携带证书式访问。通过对 Credentials 参数的设置,就可以保持跨域 Ajax 时的 Cookie。这里需要注意的是:

服务器端 Access-Control-Allow-Credentials = true时,参数Access-Control-Allow-Origin 的值不能为 '*'

/**
* Spring Controller中的方法:
*/
    @RequestMapping(value = "/corsrequest")
    @ResponseBody
    public Map<String, Object> getUserBaseInfo(HttpServletResponse response) {
        if(request.getHeader("Origin").contains("woego.cn")) {
            response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
        }
        response.setHeader("Access-Control-Allow-Credentials", "true");
        ...
}

另一种方式,在一个没有response参数的全局代码中:

HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
        .getRequestAttributes()).getRequest();
HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder
        .getRequestAttributes()).getResponse();
//改写允许访问的域名地址为真实地址,解决跨域请求携带cookie问题
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));

参考资料

Angularjs之如何在跨域请求中传输Cookie 跨域Ajax请求时是否带Cookie的设置

Last updated