跨域:跨域名
一个域名下的文件去请求和其不在同一域名下的资源文件时,就会产生跨域请求,这样是不允许的,是安全限制问题。
Ajax跨域操作时,报错:XMLHttpRequest cannot load …… ‘Access-Control-Allow-Origin’header is present on the requested resource.
跨域请求资源的解决方案:
- 通过Flash 跨域请求资源,在服务器设置一个xml文件(类似于域名菜单), 将当前域名设为请求资源域名的白名单
- 本地代理:通过服务器端中转(代理作用)来请求资源,服务器端资源请求没有跨域的限制,在在当前域名的服务器上新建php文件,请求跨域资源到该服务器上,再从客户端访问当前域名对应服务器上的php资源。 互联网上,一台台服务器是通过不同的IP来进行识别的。每台服务器上可以新建很多站点,您的网站程序就放在一个站点里面,然后在这个站点上绑定您的域名。所以一台服务器可以绑定很多个域名,也就是一个IP可以对应很多个域名,但是一个域名只能绑定到一个站点上,也就是对应一个IP。
- Script 标签
JSONP :JSON with Padding
概念理解:
- JSONP是一个非官方的协议,通过Javascript Callback的形式实现跨域访问
- JSONP通过使用JSON和<script>标签相结合的方法,可以绕过同源策略,从服务器端直接返回可执行的Javascript函数调用或JavaScript对象
- 将JSON格式的数据,使用内嵌形式,拿来使用
- JSONP已经成为各大公司的Web应用程序跨域首选,如Youtube GData, Digg, 豆瓣等
原理:Script 标签:
- HTML中的script标签可以加载外部资源:<script src = ””></script>
- 用 script标签加载的资源没有跨域限制。如加载baidu的JQuery资源
- 以前用到的script标签加载的都是.js文件,其实script标签解析的不是文件后缀名,而是文件中的内容,通过script标签可以加载网址,网址中对应文件的内容是没有变量名的JSON对象,这是问题,加载进来的数据无法引用!!
- jsonp的使用方式:内填充
<script src=”1.txt” ></script>
<script>
function fn(data){
alert(data);
}
</script>
1.txt文件中的内容为:
fn([1,2,3]);
即:在资源加载进来之前先定义好一个函数,这个函数接收一个参数(数据),函数体中利用该参数做数据处理。
然后需要的时候通过script标签加载远程文件资源,当远程文件资源被加载进来的时候,就会执行前面定义的函数,并把数据当作该函数的参数传入。
function fn(data){ <!-- 声明全局函数fn() -->
//to do sth }
<!-- <scriptsrc="1.txt"></script> 点击按钮时,动态创建 -->
<!-- 1.txt文件调用了上面定义的全局函数fn,因此才能进行访问交互 -->
window.onload = function() {
var oBtn = document.getElementById('btn');
oBtn.onclick = function() {
//当按钮点击的时候再去加载远程资源,让他执行
var oScript =document.createElement('script');
oScript.src = '1.txt';
document.body.appendChild(oScript);
}
}
利用jsonp跨域请求资源
<inputtype="button" id="btn" value="点我"/>
当点击页面上的按钮时,就会弹出1.txt中的数组[1,2,3],用法很像ajax。
这种交互方法存在以下缺点:
当要点击不同的按钮,远程访问不同的资源并在HTML文档不同的地方显示时,类似于下面这种多接口的操作太麻烦了,每次访问新的资源时,都要跟后端交互,让后端增加接口代码。
getData.php代码如下:
<?php
$t=isset($_GET['t'])?$_GET['t']:'num';
$arr1=array('1','22','333','4444','55555');
$arr2=array('a','bb','ccc','dddd','eeeee');
if ($t=='num'){
$data=json_encode($arr1);
echo 'fn1('.$data.');';
}else{
$data=json_encode($arr2);
echo 'fn2('.$data.');';
}
function fn1(data){ <!--声明全局函数 -->
var oUl1=document.getElementById('ul1');
var html='';
for (vari=0;i<data.length;i++){
html+= '<li>'+data[i]+'</li>';
}
oUl1.innerHTML=html;
}
function fn2(data){ <!--声明全局函数 -->
var oUl2=document.getElementById('ul2');
var html='';
for (vari=0;i<data.length;i++){
html+= '<li>'+data[i]+'</li>';
}
oUl2.innerHTML=html;
}
<!-- <scriptsrc="getData.php"></script> 点击按钮时,动态创建 -->
<!-- 该标签中的文件getData.php中必须调用了上面定义的函数fn1和fn2 -->
<!-- 而 RESTful API这种标准的数据格式,jsonp是不能访问的 -->
window.onload = function() {
var oBtn1 =document.getElementById('btn1');
var oBtn2 =document.getElementById('btn2');
oBtn1.onclick =function() {
//当按钮点击的时候再去加载远程资源,让他执行
var oScript = document.createElement('script');
oScript.src = 'getData.php';
document.body.appendChild(oScript);
}
//点击按钮2时也去请求一个资源
oBtn2.onclick = function() {
/当按钮点击的时候再去加载远程资源,让他执行
var oScript = document.createElement('script');
oScript.src ='getData.php?t=str';
document.body.appendChild(oScript);
}
}
利用jsonp跨域请求资源<br>
<input type="button" id="btn1" value="加载数字"/>
<ul id="ul1"></ul>
<input type="button" id="btn2" value="加载字母"/>
<ul id="ul2"></ul>
常用的前后端交互方法:
前端将想要获得的函数名传递给后端,后端根据传入的函数名做动态匹配。
如,将getData.php文件改为:
<pre name="code" class="php"><?php
$t=isset($_GET['t'])?$_GET['t']:'num';
$callback=isset($_GET['callback'])?$_GET['callback']:'fn1';
$arr1=array('1','22','333','4444','55555');
$arr2=array('a','bb','ccc','dddd','eeeee');
if ($t=='num'){
$data=json_encode($arr1);
}else{
$data=json_encode($arr2);
}
//根据客户端传过来的参数callback,动态改变输出的函数名
echo$callback.'('.$data.');';
将前端对应的JS代码的第二个网址改为:getData.php?t=str?&callback=fn2
便可正常工作,这样即使想新添加接口也不用与后端沟通,便可实现自适应。
缺点:jsonp只能访问固定格式的资源,即如上例中定义在函数callback()中的数据。对于标准的RESTful API,jsonp是无法访问的。因此,考虑用那种方式获取资源时,应综合考虑后端返回的数据格式及先有方法的优缺点。