<commit_before>前端开发需要调用后台接口时经常遇到跨域的问题，一般是设置Chrome浏览器禁用安全模式，
在启动chrome命令后面加 `--disable-web-security`，最新的版本可能还需要加一个本地的存放chrome配置的文件夹，如下，
`--user-data-dir=C:\MyChromeDevUserData`

这种方式很不错，唯一的缺点就是有时候如果不是这种方式打开的Chrome，页面要进行跨域调试时需要关闭浏览器再用上边那种方式打开才行，这时如果已经打开了一堆网页可能就比较麻烦了。

--- 

现在介绍使用Nginx的方向代理机制来解决浏览器跨域的问题

首先假设前端VUE的端口是8080， 要调用的后台接口是：http://192.168.1.111:9090/mydemo/api/getList

因为浏览器的同源策略，所以这样必然产生了跨域。

由于VUE已经占用了前端的端口8080了，所以我们用Nginx只能再设置一个新的端口，这里暂定：8888

在nginx.conf文件 http{} 块里，添加下面的代码：

```
    server {
        listen  8888;
        server_name  localhost;

        location ^~/mydemo/ {
            rewrite ^/(.*)$ /$1 break;
            proxy_pass http://192.168.1.111:9090/mydemo/;
        }

        location / {
            proxy_pass http://127.0.0.1:8080;
        }
    }
```

###   `location ^~/mydemo/ ` 一定要放在 `location /` 前面，这样所有访问后台的请求才会走这块的代理。 一般后台服务都会带着项目名，例如`mydemo`，或者加上固定的url路径前缀，主要是为了跟前端静态资源区分开来。

重启Nginx，访问 http://localhost:8888 即可。
这样就完全避免了跨域的问题，而且不限于Chrome了，使用IE、Firefox同样没有问题。



# 下面提供一种新的解决方式

后端配置

```
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.annotation.Order;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebFilter(urlPatterns = "/*", filterName = "corsFilter")
@Order(1)
public class CorsFilter implements Filter {
    @Override
    public void init(FilterConfig fc) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp,
                         FilterChain chain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) resp;
        HttpServletRequest request = (HttpServletRequest) req;
        // 由于本地和测试环境域名+端口号访问 这种方式可以解决端口号跨域问题
        if (StringUtils.isNotEmpty(request.getHeader("Origin"))) {
            response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
            response.setHeader("Access-Control-Allow-Credentials", "true");
        } else {
            response.setHeader("Access-Control-Allow-Origin", "*");
        }
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
        response.setHeader("Access-Control-Max-Age", "36000");
        response.setHeader("Access-Control-Allow-Headers", "accept,Access-Control-Request-Method,Access-Control-Request-Headers,Origin,token,x-requested-with, authorization, Content-Type, Authorization, credential, X-XSRF-TOKEN");
        response.setHeader("Access-Control-Expose-Headers", "Content-Type, Authorization, credential, Content-Disposition");
        if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
        } else {
            chain.doFilter(req, resp);
        }
    }

    @Override
    public void destroy() {
    }

}

```








---<commit_msg>commitByZsx<commit_after>前端开发需要调用后台接口时经常遇到跨域的问题，一般是设置Chrome浏览器禁用安全模式，
在启动chrome命令后面加 `--disable-web-security`，最新的版本可能还需要加一个本地的存放chrome配置的文件夹，如下，
`--user-data-dir=C:\MyChromeDevUserData`

这种方式很不错，唯一的缺点就是有时候如果不是这种方式打开的Chrome，页面要进行跨域调试时需要关闭浏览器再用上边那种方式打开才行，这时如果已经打开了一堆网页可能就比较麻烦了。

--- 

现在介绍使用Nginx的方向代理机制来解决浏览器跨域的问题

首先假设前端VUE的端口是8080， 要调用的后台接口是：http://192.168.1.111:9090/mydemo/api/getList

因为浏览器的同源策略，所以这样必然产生了跨域。

由于VUE已经占用了前端的端口8080了，所以我们用Nginx只能再设置一个新的端口，这里暂定：8888

在nginx.conf文件 http{} 块里，添加下面的代码：

```
    server {
        listen  8888;
        server_name  localhost;

        location ^~/mydemo/ {
            rewrite ^/(.*)$ /$1 break;
            proxy_pass http://192.168.1.111:9090/mydemo/;
        }

        location / {
            proxy_pass http://127.0.0.1:8080;
        }
    }
```

###   `location ^~/mydemo/ ` 一定要放在 `location /` 前面，这样所有访问后台的请求才会走这块的代理。 一般后台服务都会带着项目名，例如`mydemo`，或者加上固定的url路径前缀，主要是为了跟前端静态资源区分开来。

重启Nginx，访问 http://localhost:8888 即可。
这样就完全避免了跨域的问题，而且不限于Chrome了，使用IE、Firefox同样没有问题。



# 下面提供一种新的解决方式

## 什么是跨域
跨域，是指浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的，是浏览器对JavaScript实施的安全限制。

## 那么什么是同源策略

同源策略/SOP（Same origin policy）是一种约定，由Netscape公司1995年引入浏览器，它是浏览器最核心也最基本的安全功能，如果缺少了同源策略，浏览器很容易受到XSS、CSFR等攻击。所谓同源是指"协议+域名+端口"三者相同，即便两个不同的域名指向同一个ip地址，也非同源。

下面列出了一些常见跨域场景

URL                                      说明                    是否允许通信
http://www.google.com/a.js
http://www.google.com/b.js         同一域名，不同文件或路径           允许
http://www.google.com/lab/c.js

http://www.google.com:8000/a.js
http://www.google.com/b.js         同一域名，不同端口                不允许
 
http://www.google.com/a.js
https://www.google.com/b.js        同一域名，不同协议                不允许
 
http://www.google.com/a.js
http://192.168.1.111/b.js           域名和域名对应相同ip              不允许
 
http://www.google.com/a.js
http://x.google.com/b.js           主域相同，子域不同                不允许
http://google.com/c.js
 
http://www.domain1.com/a.js
http://www.domain2.com/b.js        不同域名                         不允许


针对跨域，目前有很多解决方案

1、 通过jsonp跨域
2、 document.domain + iframe跨域
3、 location.hash + iframe
4、 window.name + iframe跨域
5、 postMessage跨域
6、 跨域资源共享（CORS）
7、 nginx代理跨域
8、 nodejs中间件代理跨域
9、 WebSocket协议跨域


下面我们就介绍一种目前主流的跨域解决方案——跨域资源共享（CORS）

## 什么是CORS

CORS是一个W3C标准，全称是"跨域资源共享"（Cross-origin resource sharing）。 它允许浏览器向跨源服务器，发出XMLHttpRequest请求，从而克服了AJAX只能同源使用的限制。
CORS需要浏览器和服务器同时支持。目前，所有浏览器都支持该功能，IE浏览器不能低于IE10。IE8+：IE8/9需要使用XDomainRequest对象来支持CORS。
整个CORS通信过程，都是浏览器自动完成，不需要用户参与。对于开发者来说，CORS通信与同源的AJAX通信没有差别，代码完全一样。浏览器一旦发现AJAX请求跨源，就会自动添加一些附加的头信息，有时还会多出一次附加的请求，但用户不会有感觉。 因此，实现CORS通信的关键是服务器。只要服务器实现了CORS接口，就可以跨源通信。





## 后端配置
只需要配置一个过滤器即可，如下：

```
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.annotation.Order;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebFilter(urlPatterns = "/*", filterName = "corsFilter")
@Order(1)
public class CorsFilter implements Filter {

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp,
                         FilterChain chain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) resp;
        HttpServletRequest request = (HttpServletRequest) req;
        // 解决跨域问题
        if (StringUtils.isNotEmpty(request.getHeader("Origin"))) {
            response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
            response.setHeader("Access-Control-Allow-Credentials", "true");
        } else {
            response.setHeader("Access-Control-Allow-Origin", "*");
        }
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
        response.setHeader("Access-Control-Max-Age", "36000");
        response.setHeader("Access-Control-Allow-Headers", "accept,Access-Control-Request-Method,Access-Control-Request-Headers,Origin,token,x-requested-with, authorization, Content-Type, Authorization, credential, X-XSRF-TOKEN");
        response.setHeader("Access-Control-Expose-Headers", "Content-Type, Authorization, credential, Content-Disposition");
        if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
        } else {
            chain.doFilter(req, resp);
        }
    }

}


```

## 前端配置

前端配置只需要把withCredentials设置为true即可。

1.原生ajax

```
xhr.withCredentials = true;
```

2.vue框架

a.) axios设置：
```
// 前端设置是否带cookie
axios.defaults.withCredentials = true
```
b.) vue-resource设置：
```
Vue.http.options.credentials = true
```

这里假设后端服务地址为： 192.168.1.111:8080

我们需要配置一下hosts，（域名随便写）
```
192.168.1.111 server.google.com
```
这样访问 http://server.google.com:8080 也可能访问到你的后端服务了。

那么前端调用后端接口需要都写成 http://server.google.com:8080/+接口 这样的方式

访问前端也要用这种域名加端口的方式，比如本地启动了前端项目，端口是9090，那么也需要配置一下hosts，
```
127.0.0.1 front.google.com
```
就可以直接用 http://front.google.com:9090 访问前端页面了


也可以用下面这种配置方式直接设定vue启动后访问的url地址。

```
module.exports = {
  dev: {
    host: 'front.google.com', // can be overwritten by process.env.HOST
    port: 80, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
    ...
  }
}
```

## 总结一下

1、配置hosts

```
# 后端地址
192.168.1.111 server.google.com
# 前端地址
127.0.0.1 front.google.com
```

2、前端调用后端接口需要用域名+端口方式，例如 http://server.google.com:8080

3、在浏览器访问前端页面也需要用域名+端口的方式，例如 http://front.google.com

4、只要保证配置的两个域名的二级域名一样就可以了，三级域名随便。

5、这种方式只需要配置一次，如果想访问不同环境的后端服务，只需要修改hosts配置就可以了。而且部署前后端分离时，只需要修改前端调用后端接口的配置即可。









---
{'fraction_non_alphanumeric': 0.12867560573982592, 'fraction_numerical': 0.02846389084921195, 'mean_word_length': 3.6036816459122902, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 1, 'lorem ipsum': 0, 'www.': 11, 'xml': 0}, 'pii_count': 12, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4942598', 'n_tokens_mistral': 4134, 'n_tokens_neox': 4353, 'n_words': 388}