> For the complete documentation index, see [llms.txt](https://book.rizon.top/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://book.rizon.top/qian-duan/kua-yu-qing-qiu-wen-ti.md).

# 解决跨域请求问题

## 背景

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

同源策略的限制：

* 存储在浏览器中的数据，如localStroage、Cooke和IndexedDB不能通过脚本跨域访问
* 不能通过脚本操作不同域下的DOM
* 不能通过ajax请求不同域的数据

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

## 无关Cookie跨域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);
    }
}
````

## 带Cookie的跨域Ajax请求

如果这些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` 的值不能为 '\*'

```java
/**
* 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参数的全局代码中：

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

## 参考资料

[Angularjs之如何在跨域请求中传输Cookie](https://blog.csdn.net/mygrilzhuyulin/article/details/52690129) [跨域Ajax请求时是否带Cookie的设置](https://blog.csdn.net/wzl002/article/details/51441704)
