1、跨域
Ajax跨域的存在的问题:浏览器的同源策略,该策略会阻止ajax跨域访问。
同源策略(Same origin policy):它是由Netscape提出的一个著名的安全策略。
所谓同源是指,域名,协议,端口相同。
如果非同源,那么在请求数据时,浏览器会在控制台中报一个异常,提示拒绝访问。
2、解决跨域的三种方式
2.1、服务器代理
核心思想:php中哟一个函数 file_get_contents。该函数能够获取其他网站的数据。
www.hf.cn服务器a.html文件希望获取www.study.com服务器data.php文件返回的数据,但是由于同源的策略的限制,不能直接获取。
a.html文件通过ajax请求本服务器中的proxy.php文件,该文件中使用file_get_contents函数将data.php的数据获取到,然后在返回给a.html
的ajax请求。
代码实现:
a.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <script src="./jquery-1.12.4.js"></script> </head> <body> 123 <script type="text/javascript"> $.get('proxy.php','get',function(msg){ console.log(msg); },'json'); </script> </body> </html>
proxy.php
<?php echo file_get_contents('http://www.study.com/data.php'); ?>
data.php
<?php echo "321"; ?>
2.2、cors跨域——跨域资源共享
核心方法: 在服务器端(PHP文件中)声明不用进行同源限制
如果设置为 * 则是所有外部网站都可以获取数据:header('Access-Control-Allow-origin: *');
代码实现:
a.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <script src="./jquery-1.12.4.js"></script> </head> <body> <script type="text/javascript"> $.get('http://www.study.cn/data.php','get',function(msg){ console.log(msg); },'json'); </script> </body> </html>
data.php
<?php header('Access-Control-Allow-origin: http://www.study.com'); echo "321"; ?>
2.3、jsonp跨域
核心思想: 浏览器虽然有同源策略,但是 src 和 href 两个属性却可以跨域访问。 可以利用这一“漏洞”发送ajax请求。
本地案例1:
www.hf.cn的a.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <script> function a() { console.log('被调用了'); } </script> <script type="text/javascript" src="http://www.study.com/data.php"></script> </body> </html>
www.study.com/data.php:
<?php echo 'a()'; ?>
$.ajax方法跨域操作 --- jsonp方式
核心:
-
-
必须设置dataType为jsonp --- dataType: ‘jsonp’
-
必须额外设置一个jsonp参数,该参数值可以是任何英文字符串,常用callback。该函数的作用是在前端自动创建一个以该字符串为名称的函数名
本地案例:
www.hf.cn的a.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <script src="./jquery-1.12.4.js"></script> </head> <body> <script> $.ajax({ url: 'http://www.study.com/data.php', type: 'get', dataType: 'jsonp', jsonp: 'callback', //解决前后端函数名统一的问题 success: function(msg){ console.log(msg); } }) </script> </body> </html>
www.study.com/data.php:
<?php // 函数名 $callback = $_GET['callback']; // 把字符串作为函数的实参 $str = '{"a":"hello","b":"world"}'; echo $callback . "('$str')"; ?>
效果:
某宝跨域案例
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <link rel="stylesheet" href="./index.css"> <script src="./jquery-1.12.4.js"></script> <script src="./artTemplate/template-web.js"></script> <title>某宝跨域案例</title> </head> <body> <div class="box"> <input type="search" id="search" data-searchBox="search"> <div id="list"> </div> </div> <script type="text/template" id="tpl"> <ul> <% for(var i = 0; i < result.length; i++) { %> <li><%=result[i][0]%></li> <% } %> </ul> </script> <script> $('#search').on('input',function(){ var value = $(this).val(); $.ajax({ /* 网页提供 */ url:'https://suggest.taobao.com/sug?code=utf-8', data: {q:value}, type:'get', dataType: 'jsonp', jsonp: 'callback', success: function(data) { console.log(data.result); $('#list').append(template('tpl',data)); } }) }) </script> </body> </html>
显示效果:
360搜索跨域案例
简单实现跨域请求:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <style> body,ul,li { margin: 0; padding: 0; list-style: none; } .main { width: 541px; height: 46px; margin: 100px auto; position: relative; } .main .search { width: 100%; height: 100%; } .main #searchBox { display: block; width: 100%; height: 100%; padding: 5px 10px 5px 10px; border: 1px solid #19b955; box-sizing: border-box; } .main #btn { position: absolute; display: block; right: 0; top: 0; width: 20%; height: 100%; line-height: 100%; background: #19b955; font: 400 18px Arial; color: #fff; text-align: center; border: none; outline: none; } .show { width: 80%; border: 1px solid #ccc; } .show ul { width: 100%; height: 100%; } .show ul li { width: 100%; height: 20px; padding-top: 5px; padding-bottom: 5px; text-align:left; text-indent:10px; cursor:pointer; } </style> <script src="./libs/jquery.min.js"></script> </head> <body> <div class="main"> <div class="search"> <input type="text" id="searchBox"> </div> <input type="button" value="搜 索" id="btn"> <div class="show" style="display: none;"> <ul> </ul> </div> </div> <script> /* 3.增加鼠标移入样式,浏览器渲染完毕,li是keyup事件结束以后追加到html上的,如果 直接给li绑定事件,是获取不到元素的,这时我们需要事件委托 */ $(".show>ul").on("mouseover","li",function () { this.style.background = "#efefef"; }); $(".show>ul").on("mouseout","li",function () { this.style.background = "white"; }); /* 2.创建搜索引擎返回来数据的回调函数,解析数据 */ function suggest_so(data) { var results = data.result; console.log(results); var ul = document.getElementsByTagName("ul")[0]; ul.innerHTML = ""; for (var i = 0; i < results.length; i++) { var li = document.createElement("li"); li.innerHTML = results[i].word; ul.appendChild(li); } } /* 1.添加键盘事件,获取输入的值 */ document.getElementById('searchBox').onkeyup = function () { var keyword = this.value; /* 去掉数据开始和结束的空格 */ value = keyword.trim(); if(value.length > 0) { /* 显示隐藏的div */ document.getElementsByClassName('show')[0].style.display = 'block'; /* 利用 src 跨域访问 */ var tag = document.createElement("script"); tag.src = "https://sug.so.360.cn/suggest?callback=suggest_so&encodein=utf-8&encodeout=utf-8&format=json&fields=word&word=a" + value; /* 将这个script标签添加到html结构中 */ document.body.appendChild(tag); } else { document.getElementsByClassName('show')[0].style.display = 'none'; } } </script> </body> </html>
效果:
利用jQuery实现跨域:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <style> body,ul,li { margin: 0; padding: 0; list-style: none; } .main { width: 541px; height: 46px; margin: 100px auto; position: relative; } .main .search { width: 100%; height: 100%; } .main #searchBox { display: block; width: 100%; height: 100%; padding: 5px 10px 5px 10px; border: 1px solid #19b955; box-sizing: border-box; } .main #btn { position: absolute; display: block; right: 0; top: 0; width: 20%; height: 100%; line-height: 100%; background: #19b955; font: 400 18px Arial; color: #fff; text-align: center; border: none; outline: none; } .show { width: 80%; border: 1px solid #ccc; } .show ul { width: 100%; height: 100%; } .show ul li { width: 100%; height: 20px; padding-top: 5px; padding-bottom: 5px; text-align:left; text-indent:10px; cursor:pointer; } .show ul li:hover { background: #ccc; } </style> <script src="./libs/jquery.min.js"></script> <script src="./libs/artTemplate-master/dist/template.js"></script> </head> <body> <div class="main"> <div class="search"> <input type="text" id="searchBox"> </div> <input type="button" value="搜 索" id="btn"> <div class="show" style="display: none;"> </div> </div> <!-- 模板引擎 --> <script type="text/template" id="tpl"> <ul> {{each datas as value index}} <li>{{value.word}}</li> {{/each}} </ul> </script> <script> /* 2.创建搜索引擎返回来数据的回调函数,解析数据 */ function suggest_so(datas){ // console.log(datas); var html = template('tpl',{"datas":datas.result}); $('.show').html(html); } /* 1.添加键盘事件,获取输入的值 */ document.getElementById('searchBox').onkeyup = function () { var keyword = this.value; /* 去掉数据开始和结束的空格 */ value = keyword.trim(); if(value.length > 0) { /* 显示隐藏的div */ document.getElementsByClassName('show')[0].style.display = 'block'; /* 利用 ajax 跨域访问 */ $.ajax({ url:"https://sug.so.360.cn/suggest?callback=suggest_so&encodein=utf-8&encodeout=utf-8&format=json&fields=word&word=" + value, type:"get", dataType:"jsonp", jsonp:"callback", success: function (datas){ suggest_so(datas); } }) } else { document.getElementsByClassName('show')[0].style.display = 'none'; } } /* 3.增加鼠标移入样式,浏览器渲染完毕,li是keyup事件结束以后追加到html上的,如果 直接给li绑定事件,是获取不到元素的,这时我们需要事件委托 */ /* 问题:实现不了!!!用C3的hover模拟.. $('ul').on("mouseover",'li',function () { this.style.background = "#efefef"; }); $(".show>ul").on("mouseout","li",function () { this.style.background = "white"; }); */ </script> </body> </html>
jsonp封装
参看:实现一个JSONP
// 封装 function jsonp({ url, params, callback }) { return new Promise((resolve, reject) => { let script = document.createElement('script') window[callback] = data => { resolve(data) document.body.removeChild(script) } params = { ...params, callback } let arrs = [] for (let key in params) { arrs.push(`${key}=${params[key]}`) } script.src = `${url}?${arrs.join('&')}` script.setAttribute('type', 'text/javascript') document.body.appendChild(script) script.onerror = () => { reject(new Error(`fetch ${url} failed`)) document.body.removeChild(script) } }) } // 设置方法 const fn = async function (value) { let data = await jsonp({ url: 'https://sug.so.360.cn/suggest/', params: { encodein: 'utf-8', encodeout: 'utf-8', format: 'json', fields: 'word', word: value }, callback: 'suggest_so' }) console.log(data) } // 调用 fn('北京')