一、认识跨域
1.1、介绍跨域(含示例)
跨域:向一个域发送请求,如果要请求的域和当前域是不同域即为跨域。不同域之间的骑牛,就是跨域请求。
示例:
<script> //访问本地资源实际就是同域:http://localhost:5500/main.css // const url = "./main.css"; //下面这个请求就是不同域,若是我们在本地向改地址发送一个ajax请求,就会出现跨域问题! const url = "https://blog.csdn.net/cl939974883"; const xhr = new XMLHttpRequest(); xhr.onreadystatechange = () => { if (xhr.readyState != 4) return; if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) { console.log(xhr.responseText); } } xhr.open("GET", url, true); xhr.send(null); </script>
1.2、同域与不同域区别
一般一个请求地址为:https://www.imooc.com:443/course/list
组成:https(协议)://www.imooc.com(域名):443(端口号)/course/list(路径)
协议、域名、端口号、路径。
不同域指的是协议、域名、端口号只要其中一个不一样就是不同域!!!对于只是路径不一样的话是同域。
1.3、跨域请求为什么被阻止?
原因:阻止跨域请求,其实是浏览器本身的一种安全策略—同源策略!!!实际上本质后端也是响应过来的,只是浏览器在接收解析响应时会对响应的内容就是检查,若是不安全就会直接将其丢弃,才会出现这样的现象!
解决方案(后端来进行解决):①CORS跨域资源共享。②JSONP
优先使用CORS跨域资源共享,如果浏览器不支持CORS的话,再使用JSONP。
二、两种解决方案
方案1:CORS(IE10及以上选择)
认识CORS以及进行测试
CORS:简而言之就是后端发送响应前,给响应头设置Access-Control-Allow-Origin: *(也可指定单个地址,这里指的是所有地址允许)即可,浏览器接收到响应解析了到就会放行认为其是安全的。
测试:
由于需要后端来设置响应头的内容才能够实现CORS,所以这里来使用慕课网的接口来进行测试:https://www.imooc.com/api/http/search/suggest?words=js,这是慕课网的一个关键词接口,我们通过1.1中的ajax来发送请求。
成功响应:
响应头信息:
Access-Control-Allow-Origin说明
兼容性:IE10及以上版本的浏览器可以使用CORS。若是要适配IE10以下的只能使用JSONP。
Access-Control-Allow-Origin: *:表名允许所有的域名来跨域请求它,*是通配符,没有任何限制。
Access-Control-Allow-Origin: http://127.0.0.1:5500:只允许指定域名的跨域请求。(允许单个)
CORS跨域过程(核心重点):
1、浏览器发送请求。
2、后端在响应头中添加Access-Control-Allow-Origin头信息。
3、浏览器接收到响应。
4、如果是同域下的请求(比对发出的请求),浏览器不会额外做任何事情。前后端通信成功!
5、如果是跨域请求(不同域请求),浏览器会从响应头中查找是否允许跨域访问。
6、如果允许跨域(根据响应头中的Access-Control-Allow-Origin),前后端通信成功!
7、如果没找到或不包含想要跨域的域名,就会丢弃响应结果。
核心就是如果向不同域的后端发送请求,浏览器在拿到响应结果后会去解析响应头中是否有对应的Access-Control-Allow-Origin,若是该键值对为允许跨域的域名,此时通信成功!
方案2:JSONP(IE10以下选择方案)
实现方式:同样需要后端来实现JSONP,加载JSONP接口需要使用前端的script标签。
浏览器测试
我们依旧使用慕课的一个接口:https://www.imooc.com/api/http/jsonp?callback=handleResponse,其中callback=后面的可以任意设置名称。
此时前端需要通过调用指定后面跟着的函数名得到指定对象!
前端静态与动态加载JSONP接口
静态加载:其中script标签必须放在最后引用才有效
<script> // 2、使用指定callback=xxx,后面的xxx函数来接收data对象 const handleResponse = (data) => { console.log(data); console.log(typeof data); } </script> <!-- 1、使用script标签来进行加载资源(必须放置在最后) --> <script src="https://www.imooc.com/api/http/jsonp?callback=handleResponse"></script>
动态加载:就是使用js来动态创建一个dom元素并将其挂载到dom树上
<script> // 1、创建script标签并进行挂载 var s = document.createElement("script"); s.src = "https://www.imooc.com/api/http/jsonp?callback=handleResponse"; document.body.appendChild(s); // 2、使用指定callback=xxx,后面的xxx函数来接收data对象 const handleResponse = (data) => { console.log(data); console.log(typeof data); } </script>