跨域请求
浏览器为了安全性问题,做出了同源策略的限制,跨域请求是不能请求的。什么是域:域就是协议名和主机名+端口号。只有三部分都一样才能说是相同的域。相同域之间不受限制,不同域之间不能相互请求。
jsonp处理跨域请求,跨域请求很多常见的是jsonp。
平时用的<img>,<link>,<script>这些标签是不受跨域限制的。但是能不能让<script>去请求数据来请求获取json数据呢?答案是肯定的。json可以描述复杂的数据。更重要的是json格式的数据能被JavaScript原生支持。于是服务器端就可以生成json文件。这样一种解决跨域请求的方案就出来了,大家称之为jsonp。
请看一下代码
// 服务器 // jsonp跨域 app.get('/3-6-2-json-1.js',function(req,res){ res.render('3-4-1-post'); }); //3-6-2-json-1.js alert('the message from server'); //jsonp.html <!DOCTYPE html> <html> <head> <title>jsonp</title> <meta charset="utf-8"> </head> <body> <script type="text/javascript" src="http://localhost:3000/3-6-2-json-1.js"></script> </body> </html>
接下来扩展一下
// jsonp1.html <!DOCTYPE html> <html> <head> <title>jsonp</title> <meta charset="utf-8"> </head> <body> <script type="text/javascript"> function getData(data){ alert("我是本地函數,跨域請求服務器的js文件,服務器返回是:"+data.result); } </script> <script type="text/javascript" src="http://localhost:3000/3-6-2-json-1.js"></script> </body> </html> // 3-6-2-json-1.js getData({result:'this message from server'});
这样跨域就可以使用了,但是有一个问题就是如何让服务器知道本地的函数名?可以在url后传递参数
封装jsonp
function getData(data){ alert("我是本地函數,跨域請求服務器的js文件,服務器返回是:"+data.result); } // 封装jsonp url 请求的url callback回调 ajax.jsonp = function(){ // 创建动态的script标签 var script = document.createElement('script'); // 生成函数名 var time = new Date(); var funcName = 'jsonp' + time.getTime(); } // 拼接url,判断url中是否有参数 if(url.indexOf('?')>0){ url = url + '&callback=' + funcName; }else{ url = url + '?callback=' + funcName; } // 注册回电函数到全局 window[funcName] = function(data){ callback(data); delete window[funcName]; script.parentNode.removeChild(script); } // 设置script标签的src属性 script.setAttribute('src',url); // 把script 标签加入到head,请求服务得到数据 document.getElementsByTageName('head')[0].appendChild(script); } //调用代码 Ajax().jsonp('http://localhost:3000/3-6-2.js?city=tj&date=20200101',function(data){ function(data){ alert(data.city+'在'+data.date+'天气'+data.weater); } })
基于<iframe>标签
window.name属性始终存在于当前窗口所打开过的所有页面中,不会因页面的刷新和新页面的载入而重置。
实例代码:
// window.name.html <!DOCTYPE html> <html> <head> <title>window.name</title> <meta charset="utf-8"> </head> <body> <a href="./3-6-2-iframe-2.html">点击在本窗口打开并且查看window.name的值</a> <script type="text/javascript"> window.name = '这是第一个页面设置的name属性的值' </script> </body> </html> // 3-6-2-iframe-2.html <!DOCTYPE html> <html> <head> <title>3-6-2-iframe-2.html</title> <meta charset="utf-8"> </head> <body> <h3>这是在本窗口贷款的第二个嗯,在这个页面显示window.name的值</h3> <script type="text/javascript"> alert(window.name); </script> </body> </html>
升级版:
//windowName.html <!DOCTYPE html> <html> <head> <title>windowName</title> <meta charset="utf-8"> </head> <body> <button onclick="getData()">点击发起跨域请求</button> <iframe id="iframe" src="http://localhost:3000/3-6-2-iframe-data?name=ab" style="display: none"></iframe> <script type="text/javascript"> function getData(){ // 获取iframe标签对象 var iframe = document.getElementById('iframe'); iframe.src = 'about:black'; iframe.onload = function(){ var data = iframe.contentWindow.name; data = JSON.parse(data); alert(data.name + '的口号是:' + data.info); } } </script> </body> </html> // 服务器 //windowName app.get('/3-6-2-iframe-data',function(req,res){ var param = req.query.name; var data = {name:param,info:'唯我独尊'}; var data = JSON.stringify(data); res.send("<script>window.name='"+data+"';</script>"); });
封装window.name跨域请求
// 封装window.name 跨域请求 ajax.iframe = function(url,callback){ // 创建iframe标签 var iframe = document.createElement('iframe'); // 设置属性为隐蔽 iframe.style = 'none'; // 指定iframe的src属性 iframe.src = url; // 把iframe写入到body中 document.getElementsByTageName('body')[0].appendChild(iframe); // 设置标志用于判断,保证src只设定一次 var flag = true; // src只改变一次,iframe重新加载一次 ajax.onload = function(){ // 判断状态,防止重置src if(flag){ // 将域设置成同城 iframe.src = 'about:black'; // 一旦设置好后就可以获取window.name的值了 flag = false; }else{ // 获取服务器设定name var data = iframe.contentWindow.name; // 判断用户想要接收的数据类型 if(ajax.dataType == 'JSON'){ // 将json格式字符串转化为json对象 data = JSON.parse(data); } // 将数据给回调函数 callback(data); // 销毁节点 document.body.removeChild(iframe); } } }; // 考虑到兼容 if(iframe.attachEvent){ iframe.attachEvent('onload',ajax.onload); }else{ iframe.onload = ajax.onload; }