1.什么是跨域?
就是访问第三方网站,严格来说就是不符合同源策略(同源策略:协议,域名,端口都一样的叫同源,其中有一样不一样就是跨域)
http://localhost:8080/ajax
https://localhsot/tom
这俩地址之间的数据传输属于跨域
2.为什么引出跨域问题
原生ajx不支持跨域获取数据(出于安全考虑)
ajax的限制:只要你请求的url跟你所在的url不同源,就不允许获取数据。
3.怎么实现跨域
a.动态创建script标签;(最常用的方式,一个官方的名字是jsonp);
什么是jsonp?
json with padding
如何用jsonp的形式解决获取数据跨域的问题。
原理:动态创建script标签,通过scr属性发送请求,从而获取数据。(向第三方发送请求并传入接收响应数据的回调函数名,当第三方接收到响应时,会调用请求发送传过来的函数,将请求数据传入,返回一个object类型的数据)
b.document.domain+iframe的设置;
c.利用iframe和location.hash(这里的hash指的是url地址里的锚点);
d.window.name实现的跨域数据传输;
e.使用h5 postmessage;
f.利用flash.
3.1 1.跨域可以获取数据,同源同样可以获取数据
例子:同源模拟jsonp处理跨域问题。
@1用传统方式获取第三方数据(是同步的,必须放在最上面,不灵活)
jsonp_src.html
<head>
<meta charset="UTF-8">
<title>Document</title>
<script type='text//javascript' src='src='jsonp.php''> </script>
<script type='text/javascript' >
//跨域可以获取数据,那同源也可以获取数据
//传统方式通过src属性能去获取第三方数据,请求目标资源,这里文件类型任意。
//这里是获取一个php文件的内容,数据内容是一段js文本
console.log(data); //打印输出一下从服务器获取回来的数据
</script>
</head>
jsonp.php 模拟从服务器获取的数据
<?php
//这是一段代码,能够返回到jsonp.html中,会被被解析为一段js代码
echo 'var data=1;';
?>
@2函数方法名不应该写死,应该传入 参数更灵活,methodName=abc,将方法名抽成一个参数传入后台,后台通过$method=$_GET('methodName)来获取
<head>
<script type='text/javascript'>
//如何让接口的调用者决定函数名,传参
function abc(data){
console.log(data);
}
window.onload=function(){
//1.创建一个script标签,
var script=document.createElement('script');
script.src='jsonp.php?methodName=abc';
var head=document.getElementsByTagName('head')[0];
head.appendChild(script);
}
</script>
</head>
//发送的请求文件的返回类型是一个js文件
//方法名参数已随url发送过去,请求的是一个方法的调用,
//请求的是一个方法的调用,返回数据是一个object
//动态传参
<script type='text/javascript' >
//动态生成方法名 new Date().getTime()当前时间对应的毫秒数
//(Math.random()+" ")将数值变成字符串,然后.substr(2)截取掉小数点以前的整数位以及小数点
//对象属性的访问和添加方式有两种 . [可以传变量] //var obj={}
//obj.name='qq' //这里是死的写什么,就表示什么属性
//obj[name]='qq' //这里实质上是一个string,直接写表示变量name,'name'表示name属性
//核心:回调函数的创建,参数的传递(对象的本质是键值对)
var mName='jquery'+(new Date().getTime())+'_'+((Math.random()+'').substr(2));
//此处创建回调函数,随参数发送请求到服务器,服务器调用回调函数,将结果数据返回到此函数中,返回。
//在window全局作用域内,所有的变量和函数都是window的成员
//这句话的作用就是给window对象添加一个自定义属性,这个属性是个方法。
window[mName]=function(data){
console.log(data);
}
//1.创建一个script标签,回调函数callback='+mName
var script=document.createElement('script');
script.src='jsonp.php?callback='+mName;
var head=document.getElementsByTagName('head')[0];
head.appendChild(script);
</script>
</head>
//php数据
<?php
//这是一段代码,能够返回到jsonp.html中,被解析为一段js代码
// echo 'var data=1;';
// echo 'abc(123)'; //这个字符串表示函数调用,其实就是服务器调用客户端传来的回调函数
//$arr=array(1234,34,5,4);
$arr1=array('name'=>1234,'age'=>34);
//echo 'abc('.json_encode($arr1).')';//Object {name: 1234, age: 34}
$method=$_GET['callback'];
echo $method.'('.json_encode($arr1).')';
?>
//访问360天气(获取第三方数据)
<script type='text/javascript'>
var mName='jquery'+(new Date().getTime())+'_'+((Math.random()+'').substr(2));
window[mName]=function(data){
console.log(data);
}
var script=document.createElement('script');
//访问360天气的请求 _jsonp='+mName 传入接收响应数据的回调函数的名字
script.src = 'http://cdn.weather.hao.360.cn/api_weather_info.php?app=hao360&_jsonp='+mName+'&code=101010100';
var head=document.getElementsByTagName('head')[0];
head.appendChild(script);
</script>
//请求发送并传入回调函数名字
//第三方调用请求数据时传入的回调函数的名字
//第三方返回的数据,传入回调函数中,object类型的数据
//虚拟机模拟跨域获取数据
<script text='text/javascript'>
var mName='jquery'+(new Date().getTime())+'_'+((Math.random()+'').substr(2));
window[mName]=function(data){
console.log(data);
}
var script=document.createElement('script');
//'http://tom.com/weather.php? 请求数据,传入回调函数名称,以便接收响应数据
script.src='http://tom.com/weather.php?_jsonp='+mName;
var head=document.getElementsByTagName('head')[0];
head.appendChild(script);
</script>
//模拟请求数据 weather.php
<?php
$city = $_GET['_jsonp'];
//数据库查询过程省略
//select * from weather where city = $city;
$arr = array('temp'=>'35度','direction'=>'风向');
//调用发送请求时传来的回调函数
echo $city.'('.json_encode($arr).')';
?>
4.封装一个属于自己的jsonp方法
why?之前我们都是按照要求一步一步写出来的,这是面向过程的思想,面向过程代码之间的关联性太强,好多重复代码,不灵活,我们知道javascript是面向对象的语言,所以我们会封住一个jsonp的方法,将公共部分抽离出来,不确定,就是比较灵活的部分,以参数形式传入。
//先使用一下jquery里的封装好的ajax()关于jsonp的处理
<script type='text/javascript' src='js/jquery.js'></script>
<script type='text/javascript'>
$(function(){
$.ajax({
url:'http://tom.com/weather.php',
dataType:'jsonp',
jsonp:'_jsonp', //这个参数是修改回调函数参数名的,不写默认是callback
// jsonpCallback:'abc', //这是修改参数的值,不写默认按规则生成字符串作为函数名。
success:function(data){
console.log(data);
}
})
})
</script>
//第三方数据文件 tom.com/weather.php
<?php
$city = $_GET['_jsonp'];
$arr = array('temp'=>'35度','direction'=>'风向');
echo $city.'('.json_encode($arr).')';
?>
ajaxx原生虽然不能实现跨域,但是jsonp实现原理属于ajax内部的另一个分支,如果数据返回类型是text或者json,是由XMLHttpRequest对象来处理,如果数据返回类型是jsonp,则会走ajax的另一个分之,是由<script></script>标签来处理数据的
//这是ajax异步js原生实现过程
function ajaxForJson(obj){
var type='get';
var dataType='text';
var url='#';
var success=function(data){
console.log(data);
}
if(obj.type=='post'){
type=obj.type;
}
if(obj.url){
url=obj.url;
}
if(dataType=='json'){
dataType=obj.dataType;
}
//关于参数的处理
var param='';
if(obj.data && typeof obj.data=='object'){
for(var key in obj.data){
param+=key+'='+obj.data[key]+'&';
}
if(param.length>1){
param=param.substring(0,param.length-1);
}
}
if(typeof obj.success=='function'){
success=obj.success;
}
var xhr=null;
//1.创建XMLHttpRequest对象
if(window.XMLHttpRequest){
xhr=new XMLHttpRequest();
}else{
xhr=new ActiveXObject('Microsoft.XMLHTTP');
}
if(type=='get'){
param=encodeURI(param);
url+='?'+param;
}
//2.准备发送请求
xhr.open(type,url,true);
var data=null;
if(type=='post'){
data=param;
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
}
//3.发送请求
xhr.send(data);
//4.处理返回数据
xhr.onreadystatechange=function(){
if(xhr.readyState==4){ //接收到响应,并返回数据,但数据是否正常不知道
if(xhr.status==200){ //数据正常
var data=xhr.responseText;
if(obj.dataType=='json'){ //返回数据类型是json,要转成object
data=JSON.parse(data);
}
success(data);
}
}
}
}
//这是jsonpjs原生的实现原理,走的是ajax的另一个分支。
function ajaxForJsonp(obj){
if(obj.dataType=='jsonp'){
var jsonp='callback';
if(obj.jsonp){
jsonp=obj.jsonp;
}
var jsonpCallback='jquery'+(new Date().getTime())+'_'+((Math.random()+'').substr(2));
if(obj.jsonpCallback){
jsonpCallback=obj.jsonpCallback;
}
//定义回调函数
window[jsonpCallback]=function(data){
//判断是不是函数
if(obj.success && typeof obj.success=='function'){
obj.success(data);
}
}
//处理参数
var param='';
//先判断obj.data是不是对象
if(obj.data && typeof obj.data=='object' ){
for(var key in obj.data){
param+=key+'='+obj.data[key]+'&';
}
}
var script=document.createElement('script');
script.src=obj.url+'?'+param+jsonp+'='+jsonpCallback;
var head=document.getElementsByTagName('head')[0];
head.appendChild(script);
}
}
//这就是模拟$.ajax()方法中ajax异步和jsonp的内部原理
function ajaxsum(obj){
if(obj.dataType=='jsonp'){
ajaxForJsonp(obj);
}else{
ajaxForJson(obj);
}
}
//这是个跨域请求
<script type='text/javascript' src='js/jsonp_ajax.js'></script>
<script type='text/javascript'>
ajax({
url:'http://tom.com/weather.php',
// url:'ajaxphp.php',
dataType:'jsonp',
jsonp:'_jsonp',
jsonpCallback:'bcd',
data:{
name:'zs',
age:12
},
success:function(data){
console.log(data);
}
})
</script>
###json和jsonp的内部走的是ajax()的两个分支。
//返回数据是函数调用,就是jsonp
bcd({"uname":"zs","$age":"12"})
//这样的数据就是json格式的字符串
{"uname":"zs","$age":"12"}
ie8以上才能用
post.message()---h5新特性,有兼容性
可以用flash ---考虑兼容的话
-
无相关信息