跨域,以及全部解决方案
一、跨域问题产生的前提条件--必须有浏览器,没有浏览器就没有跨域问题
跨域问题是浏览器为了解决 一些安全问题而提出的一个解决方案:同源策略,
服务器之间的访问是不存在跨域问题的;
二、什么叫同源?
浏览器里面的一个url地址:
https://127.0.0.1:8080/user, 包含 协议(https)、域名主机(127..0.0.1)、端口号:8080,、uri(/user) 四个部分,前面三部分 必须保持完全一样,这个叫浏览器的同源策略;
三、举个栗子
1.我打开了一个www.baidu.com,在页面放一个异步ajax请求到谷歌,即,在我的页面上,调用谷歌的接口,这个请求就会被浏览器拦截下来。
那么问题来了,为什么要有同源策略呢?再举个栗子。。。
假如有个浏览器,打开了2个标签,分别访问了 a网站和b网站,a网站如果向b网站发送ajax请求,并且带上了b网站的cookie,那么就能获取b网站的状态
如下图,基于同源策略每个网站都有自己独立的cookie.并且都是相互隔离的
四、解决跨域的几种常见方法
1.被请求方后端解决:被跨域请求的一方的服务器,设置响应头,支持数据接口的跨域传递
respones.addHeader("Access-Control-Allow-origin","请求方的url,*代表所有人都可以跨域请求") respones.addHeader("Access-Control-Max-age","10秒内") respones.addHeader("Access-Control-Allow-Method","GET") respones.addHeader("Access-Control-Allow-Headers","xxx")
2.SpringBoot解决跨域问题的两种方案:
a、通过给方法或者类加注解的形式,@CrossOrigin。
b、继承接口,重写addCorsMappings方法。
第一种方式:
@RestController @CrossOrigin("http://localhost:8081")//制定来源。可以写成*表示所有的来源 public class BaseController { @GetMapping("/hello") public String testGet(){ return "get"; } @PutMapping("/doPut") public String testPut(){ return "put"; } }
第二种方式:
@Configuration public class WebMvcConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**").allowedOrigins("http://localhost:8081")//同样这里也可以写成*表示所有的来源 .allowedHeaders("*") .allowedMethods("*") .maxAge(30*1000); } }
注意点:
路径来源的写法问题:localhost 和127.0.0.1 在Springboot中表示的是不同的字符串,校验会有异常
如果后台指定路径来源为:http://localhost:8081
那么在浏览器里访问前端页面的时候,必须用 http://localhost:8081,不可以写成127.0.0.1或者本机ip地址。否则还是会报跨域错误。
3.我用我自己的服务器去请求,绕过浏览器的同源策略-- 反向代理
a网站的网页上想要拿到b网站的数据,
我后端拦截了一个a网站的跨域的请求,用我的a网站后端服务器代替浏览器去请求b网站,后端进行交互,后端服务器拿到数据后
4.nginx静态服务器,反向代理--在前端解决跨域
网页a,访问自己域里面的nginx代理服务器中的资源,代理服务器后端转发到b服务器里面去,拿到数据给网页a;
配置反向代理:
nginx 目录:conf->nginx.conf
server { listen 443; server_name www.baidu.com; //在这个服务器上 443 端口只要有请求进来,就进行下面的重定向 location / { //只要匹配到 / 的uri就跳转到下面这个地址
//用于处理uri不一致的情况,假如原生请求 是 127.0.0.1:8081/api/user
//转发到127.0.0.1:8082/user,把路径上的地址api去除掉
rewrite ^api/(.*)$ /$1 break; proxy_pass https://www.google.com:443; proxy_connect_timeout 600; proxy_read_timeout 5000; }
/**下面是缺省值*/
location / { //只要匹配到/d的,就跳转到 下面这个页面
root html;
index index.html index.htm;
}
}
5.jsonP。最古老的方式
利用了浏览器里面的一些标签,天然支持跨域
//这个是a网站 127.0.0.1:8081 页面a.html中的一个方法,
<script>
function cross(data){
console.log(data)
}
</script>
<script src ="http://127.0.0.1:8082/cross"></script> //只支持get请求
@RequestMapping("/cross") public String cross(HttpServletResponse response){ return "cross(123)"; }
加载a.html-->访问 “http://127.0.0.1:8082/cross”-->返回了给a.html :"cross(123)”字符串-->a.html 执行了 cross(123),相当于执行了 ,function cross(data){ console.log(123)}->拿到123数据;
只能支持get请求,标签不好发post请求,不像表单,你能发post请求;
总结:
跨域解决实际上有:3种方式:
1.目标服务器支持跨域
2.浏览器访问本机服务器,然后内部对跨域请求进行转发
3.利用html的部分标签支持跨域特点进行跨域get请求访问
,