黑马程序员技术交流社区
标题: Ajax的使用以及跨域(下) [打印本页]
作者: 西安中心教研部 时间: 2017-7-31 00:13
标题: Ajax的使用以及跨域(下)
上一篇文章中我们实现了自己的myAjax封装方法,具体是模仿着jQuery的思路,其实真正的jQuery的ajax方法中,还考虑到另外一个问题的处理,那就是跨域。
在讲跨域之前呢,我们先来回想一下,我们学习ajax的目的是什么?其实学习ajax的目的很简单,就是为了获取到服务器的数据。典型的场景比如说,我们通常在注册界面需要输入用户名和密码,在输入完用户名,光标切换到密码输入框的时候,这时候往往在用户名输入框的后面会有一个提示,告知你所输入的用户名是否可用,也就是是否有别人已经使用了该用户名进行注册。对于前端界面来说,我们必然是不知道用户名究竟有没有被别人使用过,此时只有让服务器告诉我们用户名有没有被使用过。所以此时我们需要访问服务器给我们提供的一个接口地址,调用这个接口地址,传入对应的参数就能够得到数据,这个数据就是服务器告诉我们该用户名是否可用的数据。所以在这时,我们就需要访问服务器的数据,所以就需要使用ajax.
所以使用ajax,就是为了异步获取服务器的数据。
那什么是跨域呢?这里就需要提到我们使用ajax时的一个限制,那就是同源策略。
所谓的同源策略就是你要使用ajax的前端界面,和你需要访问的服务器地址必须是同域名、同端口,同协议,否则不允许访问。
如果非要用ajax访问非同源的服务器地址,那么浏览器就会报如下的错误:
但是在前端界面访问非同源的服务器的这种需求是非常常见的,比如在前端界面中获取天气数据,天气数据肯定是存在于别人的服务器上的,我们如果不能使用ajax进行访问的话,那么该怎么办呢?这里就需要使用到跨域了。
所以,先把概念理解清楚。不管是ajax还是跨域,都是为了访问服务器数据。Ajax是为了访问自己服务器的数据,跨域是为了访问别人服务器的数据。
概念理解清楚之后,我们就来看看跨域怎么来做。Ajax是无论如何都无法访问非同源服务器的地址的。所以接下来说的跨域内容其实和ajax没有啥关系。大家先把ajax暂时忘了。
跨域的实现其实是借助了script标签,我们在script标签中通常会为这个标签写一个src属性,用来制定需要使用的js文件。src的值可以是本服务器的一份js文件,也可以是互联网上某一个链接的js文件。说白了,跨域的实现就是使用script的src属性,指向一个别人服务器的链接地址。
在上诉代码中,第一个src的标签指向了外部的一个js文件,这个文件的内容如下
很简单,就是定义了一个变量haha,以及一个方法hehe().
因为第一个script标签引入了这份文件,所以在第二个script标签中,我就可以直接使用haha这个变量和hehe这个方法了,这个过程应该是很好理解的。
所以,大家记着一句话,跨域的实现就是通过script标签指向一个外部的js文件,这个js文件的内容就是一段js代码。
下面我们稍微变一下,如果我们指向的这个外部js文件,它当中的内容就是一个方法调用,那又如何呢?比如:
可以看到test2.js中的内容就是一个函数调用,调用了foo这个函数。如果在前端界面的script标签中指向test2.js文件,那么会怎么样呢?
此时浏览器会报一个错,如下:
它说foo没有定义。因为script引入的外部js文件恰好是一个方法调用,当浏览器加载完这个script标签的时候,就会执行这个js文件中的内容,而这部分内容恰好是一个方法调用,浏览器中没有定义这个foo方法,自然就会报这个错误了。那我们可以尝试着定义一个foo方法。
再次刷新这个界面,我们会发现浏览器不会报找不到foo这个错误了,并且还会打印出123,如下:
看到这里,大家有没有发现,后台的123已经成功的传到了前端界面了。
所以,修改一下之前的描述,跨域的本质其实就是利用script标签引入一个外部文件,这个文件的内容就是一个js的方法调用。数据是通过这个方法调用的参数传递到前端的。
看到这里如果有不明白的地方,那么请从头再看一遍,理解之后再看下面的内容。
我们刚才是通过一个script标签,指定src属性,这种做法有一个弊端,就是src的路径必须事先被写死在界面,无法进行动态修改。想想一个场景,我们在输入框中输入城市的名称,点击查询按钮的时候,我们希望从别人的服务器地址中得到这座城市的天气信息,按照最基本的理解应该是要访问一个服务器地址,如
http://www.tianqi.com?city=北京 要类似于这种形式,北京这两个字是用户输入的,我们无法事先写死在src的路径中,那么就需要我们通过js代码动态的获取输入框中的内容,比如北京,然后自己动态创建script标签,手动拼接一个路径,然后制定给src中,如:
上述代码就是动态创建script标签,动态的指定src属性,然后追加到head标签中。
这样浏览器就会去获取
http://www.tianqi.com?city=北京 这个网址的数据。如果这个网址的内容刚刚好是result("天气数据是:xxxxx");这样一个js的函数调用,那么我们就可以在自己界面中的result方法中获取到天气数据了。注意,我说的是
如果返回的数据是这样的话。
接下来我们来解决另外一个问题,那就是我们自己在界面中定义的方法的名称问题。我们刚才一共举了两个例子,服务器会返回foo("123");和result("天气数据是:"); 那就要求我们必须得在前端界面中先写好foo的方法或者result方法,事先写好,等着被服务器的返回调用。
那么这个方法名称我们可以自定义吗?从技术实现的角度来说,当然是可以的。既然我们都通过参数的方式将城市名称传递给服务器了,那么我们当然也可以将本界面中事先写好的方法名称传递给服务器,服务器得到这个名称之后,就改变一下它的数据返回就可以了。
我们在src属性中,多传一个参数callback,服务器得到这个callback的时候,就相当于得到了getTianqiResult这个字符串,在服务器数据返回的时候,返回的数据就发生了改变,为
getTianqiResult("天气数据是:");
换句话说,就是,前端自定义了回调方法的名称。当然,这个是得在服务器能够知道通过callback这个key值来获取方法名称的前提下。
下面我们把刚才写的那段js代码进行封装,封装到一个方法中去,这样调用起来会更加的方便。
function cross(obj){
// jsonp仅仅支持get请求
var defaults = {
url : '#',
dataType : 'jsonp',
jsonp : 'callback',
data : {},
success:function(data){}
}
//使用传递进来的obj中的值替换defaults中的值
for(var key in obj){
defaults[key] = obj[key];
}
// 这里是默认的回调函数名称
var cbName = 'xixi';
if(defaults.jsonpCallback){
cbName = defaults.jsonpCallback;
}
// 这里就是回调函数,调用方式:服务器响应内容来调用
// 向window对象中添加了一个方法,方法名称是变量cbName的值
window[cbName] = function(data){
defaults.success(data);//这里success的data是实参
}
var param = '';
for(var attr in defaults.data){
param += attr + '=' + defaults.data[attr] + '&';
}
if(param){
param = param.substring(0,param.length-1);
param = '&' + param;
}
var script = document.createElement('script');
script.src = defaults.url+ '?' + defaults.jsonp+ '=' + cbName + param;
var head = document.getElementsByTagName('head')[0];
head.appendChild(script);
}
用这个方法来实现之前说过的获取天气数据就变成了下面这个样子:
注意:jsonp的值是服务器规定好的,比如服务器告诉你它识别的是cb,那么你的jsonp的值就要是jsonp:cb,而jsonpCallback可以不传递,因为在方法封装中有默认值。
下面我们来看看几个网上存在的jsonp接口,如下:
这个地址是得到百度的提示关键字,wd指的是你想查询的关键字,cb是服务器需要获取到返回方法的key值,使用上面这个链接访问得到的数据如下:
如果我们将cb的值换一下,变为hoho,url地址是
看出规律了把,服务器会识别cb这个key值,得到返回的方法调用名称。使用jQuery的调用和使用我们自己封装的cross方法类似,如下:
这个地址是得到淘宝的提示关键字,q就是关键字的key值,调用如下:
3、
这个地址是获取天气信息,app是固定的,code是城市的编码,调用如下:
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) |
黑马程序员IT技术论坛 X3.2 |