目录
1.架构设计
1.1 简单描述
2.跨域Cors原理及科普
2.1 跨域是什么?
2.2 什么情况下会发生跨域?
2.3 如何避免跨域?
3.跨域解决案例
3.1 介绍下遇到的实际情况,直接上家伙
3.2 nginx作为反向代理使用,直接上配置
3.3 Springboot服务端全局Cors配置代码
4.该问题的解决启蒙于如下大佬
1.架构设计
1.1 简单描述
- 前端发起post请求;
- nginx收到post请求并处理,代理跳转到网关zuul的地址;
- 这套架构所处的环境详细描述一下:
- 前端是在本地笔记本上测试即IP为localhost或者127.0.0.1;
- nginx1.16和Springboot2.0微服务项目是在购买的阿里云服务器上面;
- 本地c:\Windows\System32\Drivers\etc\hosts文件里面添加ip地址加域名的映射关系;
- 阿里云服务器的/etc/hosts 里面也加上127.0.0.1 www.xxx.com映射关系
2.跨域Cors原理及科普
2.1 跨域是什么?
跨域,指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对javascript施加的安全限制。同样的接口情况下,postman或者java、python写的一些请求都可以得到返回的数据,但是浏览器则不行,必须解决浏览器的安全限制,才能进行访问,如果不解决的话,就会一直报错:
浏览器端
nginx端
2.2 什么情况下会发生跨域?
所谓同源是指,域名,协议,端口均相同,不明白没关系,举个栗子:
http://www.123.com/index.html 调用 http://www.123.com/server.php (非跨域)
http://www.123.com/index.html 调用 http://www.456.com/server.php (主域名不同:123/456,跨域)
http://abc.123.com/index.html 调用 http://def.123.com/server.php (子域名不同:abc/def,跨域)
http://www.123.com:8080/index.html 调用 http://www.123.com:8081/server.php (端口不同:8080/8081,跨域)
http://www.123.com/index.html 调用 https://www.123.com/server.php (协议不同:http/https,跨域)
请注意:localhost和127.0.0.1虽然都指向本机,但也属于跨域。
浏览器执行javascript脚本时,会检查这个脚本属于哪个页面,如果不是同源页面,就不会被执行。
2.3 如何避免跨域?
这个鄙人感觉如果从前端访问的话,不能幸免,只能进行以下三面的设置才能从根本上解决。
起初我们打算让前端自己解决,可以始终解决不了,当我意识到问题可能前端解决不了的时候,我就把问题定位在了nginx,从这里开始了小编的败笔之路,因为小编一直在搞数据方面的工作,真正接触web也是头一次,遇到跨域更是第一次,网上各种资料海找,最终的解决办法总是千变一律,当一遍一遍修改nginx的nginx.conf的server而不通的时候,小编发现有些地方始终想不明白为什么origin始终为null,而且提示如下:nginx提示403 20即(服务器已经接收到请求,但是禁止处理),着实把我拿住了,后来又想了一下,应该是服务端哪里有问题,结果找到了,漏了一个配置项就是
addAllowedOrigin("null")
配置好之后,从新打jar包,测试通过。
3.跨域解决案例
3.1 介绍下遇到的实际情况,直接上家伙
//前端post请求的小demo,配套的.js文件没有上传,如果需要的同志请密我。
<html>
<head>
<meta charset="utf-8"/>
<title>testinter</title>
</head>
<body>
<div>
<input type="text" value="xxxxxx@qq.com" class="emailInput"><button class="btnSend">发送邮箱验证码</button>
</div>
<div><button class="btnCheck">实现用户数据的校验</button></div>
<script src="./js/jquery-3.4.1.min.js"></script>
<script>
$(".btnSend").click(function(){
let fd=new FormData();
fd.append("mailbox",$(".emailInput").val());
fd.append("unix_time",Math.floor(new Date().getTime() / 1000))
$.ajax({
url: 'http://www.xxx.com:9090/api/user/code',
type: 'post',
processData: false,//重要
contentType: false,//重要
data: fd,
success: function (res) {
alert(JSON.stringify(res));
}
});
});
</script>
</body>
</html>
3.2 nginx作为反向代理使用,直接上配置
//nginx的server配置
server {
listen 9090;
server_name www.xxx.com;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
location /{
proxy_pass http://127.0.0.1:9000; //反向代理的地址加端口号
proxy_connect_timeout 600;
proxy_read_timeout 600;
}
}
3.3 Springboot服务端全局Cors配置代码
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
/**
* 使用CORS,用于解决ajax跨域访问问题
*/
@Configuration
public class CorsGlobalConfig {
private static final Logger logger = LoggerFactory.getLogger(CorsGlobalConfig.class);
@Bean
public CorsFilter corsFilter() {
//1.添加CORS配置信息
CorsConfiguration config = new CorsConfiguration();
//1) 允许的域,不要写*或者null,否则cookie就无法使用了,但是本地测试的时候可以无法避免使用null
config.addAllowedOrigin("http://www.xxx.com");
config.addAllowedOrigin("null");
//2) 是否发送Cookie信息
config.setAllowCredentials(true);
//3) 允许的请求方式
config.addAllowedMethod("OPTIONS");
config.addAllowedMethod("HEAD");
config.addAllowedMethod("GET");
config.addAllowedMethod("PUT");
config.addAllowedMethod("POST");
config.addAllowedMethod("DELETE");
config.addAllowedMethod("PATCH");
// 4)允许的头信息
config.addAllowedHeader("*");
config.setMaxAge(3600L);
//2.添加映射路径,我们拦截一切请求
UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
configSource.registerCorsConfiguration("/**", config);
//3.返回新的CorsFilter.
return new CorsFilter(configSource);
}
}