Ajax - 跨域请求

本文为原创作品。欢迎转载,转载请注明出处:林东洲的博客 | Lindz Blog

Ajax概念

Ajax全称为:'Asynchronous Javascript And XML',即异步Javascript和XML,指的是一种创建交互式网页开发技术。

注意,Ajax是一种技术,它并不是一门编程语言。

简单说来,传统的网页如果需要更新内容,就必须要重新加载整个页面。

而通过Ajax在后台与服务器进行少量的数据交换,可以使网页实现异步更新。这就意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新

例:


Ajax请求

比如我在百度上搜索ajax,其实我并没有点击‘百度一下‘按钮进行提交表单,但是页面已经向后台发起ajax请求获取数据,并将获取到的数据在页面上进行局部更新。

Ajax实战

了解了Ajax的概念之后,接下来就可以学习如何发起Ajax请求了。

在学习Ajax之前首先来创建一个form表单:

<form>
    <label>Name:<input type='text' id="name" name="name"/></label> <br>
    <input type="submit" value="提交" id='submit'>
</form>
<div>Result:<span id="result"></span></div>

表单中有个输入框和提交按钮,还有一个用来存储结果的div。
效果:

Form表单

Ajax对象创建

Ajax核心是 Javascript对象 XMLHttpRequest。在创建Ajax对象前需要对所使用的浏览器进行判断来创建不同的实例。

var request;
if(window.XMLHttpRequest){
    request = new XMLHttpRequest();
}else{
    request = new ActiveXObject('Microsoft.XMLHTTP');
}

通过检测window对象中是否有XMLHttpRequest属性来确定浏览器是否支持标准的XMLHttpRequest。

注意,请不要用浏览器的navigator.userAgent来检测浏览器是否支持某个Javascript特性。因为这个字符串可以伪造,而且一般不会采用通过IE的版本判断Javascript特性。

当然也可以使用try catch语句来创建XMLHttpRequest对象。

var request = null;
try{
    request = new XMLHttpRequest();
}catch(e){
    try{
        request = new ActiveXObject('Msxml2.XMLHTTP');
    }catch(e){
        request = new ActiveXObject('Microsoft.XMLHTTP');
    }
}

基本上常用的创建Ajax对象的方式就是这两种,可以选择封装在一个函数中。

XMLHttp=new XMLHttpRequest()已经被大多数现代标准浏览器所支持。
但为了兼容IE浏览器,按微软的方式:XMLHttp=new ActiveXObject("Msxml2.XMLHTTP") 支持IE6+的版本。
如果捕获错误,则尝试更老的方法:XMLHttp=new ActiveXObject("Microsoft.XMLHTTP") 支持IE5.5+的版本。

设置回调函数

在创建Ajax请求后,要先设置onreadystatechange回调函数(即在请求数据返回后进行的操作)。在回调函数中通常我们只需通过readyState === 4判断请求是否完成。如果已完成,再根据status === 200 判断是否是一个成功的响应。

readyState值:(1.2.3.4.5)

  1. 请求未初始化
  2. 服务器连接已建立
  3. 请求已接收
  4. 请求处理中
  5. 请求已完成,且响应已就绪

code:

request.onreadystatechange = function () {
    if (request.readyState === 4){      
        if (request.status === 200){      
            document.getElementById('result').innerHTML = request.responseText;       
        }
    }
}

发送请求

接下来就是要设置XMLHttpRequest对象中的open()方法,open()方法一共接受三个参数,第一个参数指定是GET还是POST,第二个参数指定URL地址,第三个参数指定是否使用异步发送请求,默认值是true,所以可以不用填写。

注意:千万不要把第三个参数设置为false,否则浏览器将停止响应,直到Ajax请求完成,如果这个请求耗时10秒,那么10秒内你会发现浏览器处于'假死'状态。

最后调用send()方法才算真正发送请求,GET请求不需要参数,POST请求需要把body部分以字符串或者FormData对象传进去。

code:

document.getElementById('submit').onclick = function () {
    var url = 'index.php?' +'name=' + document.getElementById('name'); 
    request.open('GET',url,true);
    request.send();
    return false;
}

给提交按钮绑定一个点击事件,在点击的时候将请求数据发送给后台,return false避免表单提交。

这样Ajax请求就完成了,已经可以实现不刷新页面局部刷新。

后台代码

这里我使用php来完成实例。

$a[]="Anna";
$a[]="Brittany";
$a[]="Cinderella";
$a[]="Diana";
$a[]="Eva";
$a[]="Fiona";
$a[]="Gunda";
$a[]="Hege";
$a[]="Inga";
$a[]="Johanna";
$a[]="Kitty";
$a[]="Linda";
$a[]="Nina";
$a[]="Ophelia";
$a[]="Petunia";
$a[]="Amanda";
$a[]="Raquel";
$a[]="Cindy";
$a[]="Doris";
$a[]="Eve";
$a[]="Evita";
$a[]="Sunniva";
$a[]="Tove";
$a[]="Unni";
$a[]="Violet";
$a[]="Liza";
$a[]="Elizabeth";
$a[]="Ellen";
$a[]="Wenche";
$a[]="Vicky";

$name = $_GET['name'];
        
if(strlen($name) > 0){
    $result = '';
    for($i = 0; $i < count($a); $i++){
        if(strtolower($name) == strtolower($a[$i])){
            $result = "find the person: $a[$i]";
        }
    }
}
if($result == ''){
    $result = "Can't find the person: $name";
}
echo $result;

这样前后端就可以跑通了。

测试

测试
测试

安全限制

注意到了上面URL使用的相对路径,如果将它改成绝对路径比如:

var url = 'http://127.0.0.1:63342/htdocs/ajax/request.php?name=' + document.getElementById('name').value;

将会报错,在Chrome的控制台里,还可以看到错误信息。

这是因为浏览器的同源策略导致的。默认情况下,JavaScript在发送Ajax请求时,URL的域名必须和当前页面完全一致。

完全一致的意思是,域名要相同(www.example.comexample.com不同),协议要相同(http和https不同),端口号要相同(默认是:80端口,它和:8080就不同)。有的浏览器口子松一点,允许端口不同,大多数浏览器都会严格遵守这个限制。

跨域请求方法

一、是通过Flash插件发送HTTP请求,这种方式可以绕过浏览器的安全限制,但必须安装Flash,并且跟Flash交互。不过Flash用起来麻烦,而且现在用得也越来越少了。

二、是通过在同源域名下架设一个代理服务器来转发,JavaScript负责把请求发送到代理服务器:

'/proxy?url=http:/www.example.com'

代理服务器再把结果返回,这样就遵守了浏览器的同源策略。这种方式麻烦之处在于需要服务器端额外做开发。

三、JSONP

即JSON with Padding,是JSON的一种“使用模式”,可用于解决主流浏览器的跨域数据访问的问题。

它有个限制,只能用GET请求,并且要求返回JavaScript。这种方式跨域实际上是利用了浏览器允许跨域引用JavaScript资源。

即Web页面上调用Js文件时可以不受跨域限制的影响,不仅如此,凡是拥有'src'这个属性的标签都拥有跨域的能力,比如:script, img, iframe标签。

代码如下:

var jsonp = document.createElement('script');
jsonp.type = 'text/javascript';
jsonp.src = 'http://www.example.com/remote.js';
document.getElementsByTagName('head')[0].appendChild(jsonp);

四、CORS

Cross-Origin Resource Sharing 跨域资源共享, CORS是一种允许当前域(domain)的资源(比如html/js/web service)被其他域(domain)的脚本请求访问的机制。

注:如果浏览器支持HTML5,那么就可以一劳永逸地使用新的跨域策略:CORS了。

在了解CORS前,先来搞清楚概念:

Origin表示本域,也就是浏览器当前页面的域。当JavaScript向外域(如sina.com)发起请求后,浏览器收到响应后,首先检查Access-Control-Allow-Origin是否包含本域,如果是,则此次跨域请求成功,如果不是,则请求失败,JavaScript将无法获取到响应的任何数据。

CORS

假设本域是my.com,外域是sina.com,只要响应头Access-Control-Allow-Origin为http://my.com,或者是*,本次请求就可以成功。

可见,跨域能否成功,取决于对方服务器是否愿意给你设置一个正确的Access-Control-Allow-Origin,决定权始终在对方手中。

服务器端对于CORS的支持,主要就是通过设置Access-Control-Allow-Origin来进行的,可以添加header头:

//php
header("Access-Control-Allow-Origin: http://www.example.com");

上面这种跨域请求,称之为“简单请求”。简单请求包括GET、HEAD和POST(POST的Content-Type类型 仅限application/x-www-form-urlencoded、multipart/form-data和text/plain),并且不能出现任何自定义头(例如,X-Custom: 12345),通常能满足90%的需求。

注:现代浏览器一般都是用JSONP或者CORS来完成跨域请求。

CORS与JSONP相比,更为先进、方便和可靠。

  1. JSONP只能实现GET请求,而CORS支持所有类型的HTTP请求。
  2. 使用CORS,开发者可以使用普通的XMLHttpRequest发起请求和获得数据,比起JSONP有更好的错误处理。
  3. JSONP主要被老的浏览器支持,它们往往不支持CORS,而绝大多数现代浏览器都已经支持了CORS。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 161,513评论 4 369
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,312评论 1 305
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 111,124评论 0 254
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,529评论 0 217
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,937评论 3 295
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,913评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,084评论 2 317
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,816评论 0 205
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,593评论 1 249
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,788评论 2 253
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,267评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,601评论 3 261
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,265评论 3 241
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,158评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,953评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,066评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,852评论 2 277

推荐阅读更多精彩内容