平时用惯了jQuery.ajax之类的方法,却时常忽略了它背后的实现,本文是学习了AJAX基础及几种跨域解决方案之后的一些收获。

一、AJAX——XMLHttpRequest

谈起Ajax我们都很熟悉,它的核心对象是XMLHttpRequest(简称XHR)。

1.创建对象:

在ie7及以上版本支持原生的写法创建该对象。

var xhr=new XMLHttpRequest();

2.发送请求:

open(type,url,isasync):第一个参数是请求类型(get,post),第二个参数是要请求的url,第三个参数是bool值表示是否为异步请求。该方法没有真正的发送请求,只是启动了一个请求以备发送。

send(body):该方法用来真正的发送请求,参数是请求真正要发送的数据内容。参数是必填项,即便不需要向服务器发送内容,也要传递参数null。

【备注】在get请求中,如果url结尾有查询字符串,那么必须先对其键和值都要进行encodeURIComponent()编码。

3.响应结果:请求的响应结果会自动复制到xhr对象的属性中。

  • status:响应结果的状态码。
  • statusText:响应结果状态说明。
  • responseText:响应返回的文本结果主体;
  • responseXML:如果响应的内容类型为"text/xml",那么结果会以XML DOM的格式赋值在该属性中。如果请求结果是非XML格式,该属性为null。

4.异步请求

大多数情况下我们都需要使用异步请求,此时可以通过检测请求的readyState来判断请求是否已经完成。实际上,每次readyState属性改变时都会触发一次onstatechange事件。readyState属性有五种取值情况:

  • 0:未初始化,也就是还未调用open()方法;
  • 1:启动,已经调用open()方法,尚未调用send()方法;
  • 2:发送,已经调用send()方法,还未收到响应;
  • 3:接收。已经接收到一部分响应结果数据;
  • 4:完成。已经接收到全部响应数据,可以在客户端调用了(最常用)。

【备注】为了保证浏览器兼容性,需要在调用open()方法之前指定onreadystatechange事件处理程序。

5.自定义HTTP请求头

setRequestHeader(key,value):发送自定义消息头。最常用的场景是在post请求中模拟表单提交:xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

【备注】该方法必须在open()之后send()之前调用。

6.简例 demo1.html:

var obj= document.getElementById("result");   //创建XHR对象   var xhr = new XMLHttpRequest();//状态变化事件xhr.onreadystatechange=function(){obj.innerHTML+="readyState:"+xhr.readyState+"<br/>";//请求完成if(xhr.readyState==4){//响应结果    if ((xhr.status==200) || xhr.status == 304){var msg="status:"+xhr.status+"<br/>";msg+="statusText:"+xhr.statusText+"<br/>";msg+="responseText:"+xhr.responseText;obj.innerHTML+=msg;} else {alert("请求失败: " + xhr.status);} }}  //启动请求   xhr.open("get", "weather.json", true);//自定义HTTP头xhr.setRequestHeader("testheader","hello");//发送请求xhr.send(null);

二、XHR进度事件

1.load事件

load事件是在响应结果接收完毕时调用,可以用来简化readystatechange事件。不过,只要浏览器接收到结果就会触发该事件,因此还需要自行判断响应状态status。

xhr.οnlοad=function(){if ((xhr.status==200) || xhr.status == 304){                          obj.innerHTML+="responseText:"+xhr.responseText;} else {alert("请求失败: " + xhr.status);} }

2.progress事件

progress事件会在浏览器接收数据的过程中周期性触发。onprogress事件处理程序可以接收到event对象参数,其中event.targe是xhr对象,它还有三个重要的属性:

  • lengthComputable:布尔值,表示进度是否可用;
  • loaded:已经接收的字节数;
  • total:根据响应头中的Content-Length预期需要接收的总字节数。
xhr.οnprοgress=function(event){if(event.lengthComputable){objstatus.innerHTML=event.loaded+"/"+event.total;}}

三、跨域资源共享(CORS)

XHR的一个主要约束是同源策略,即:相同域、相同端口、相同协议,可以通过跨域资源共享CORS(Cross-Origin Resourse Sharing)实现跨域资源共享。其基本思想是通过自定义HTTP头让浏览器与服务器沟通,从而确定是否正常响应。如果服务器允许请求,则在响应头添加"Access-Control-Allow-Origin" 来回发源信息.

1.IE对CORS支持——XDR(XDomainRequest)

IE中使用XDR对象实现CORS,它的使用与XHR对象类似,也是实例化后调用open()和send()方法。不同的是,XDR的open()方法只有两个参数:请求类型和URL。

xhr=new XDomainRequest();
xhr.open(method,url);
xhr.send();

2.其他浏览器支持CORS——原生XHR

大多数浏览器的XHR对象原生支持CORS,只需要在open()方法中传入响应的url即可。

3.跨浏览器支持CORS

综合以上两种情况,可以实现跨浏览器的CORS。检查XHR是否支持CORS的最简单方式是检查 withCredentials属性,然后结合检查XDomainRequest对象是否存在即可。

function createCORSRequest(method,url){//创建XHR对象   var xhr = new XMLHttpRequest();//启动请求   if("withCredentials" in xhr){xhr.open(method,url,true);}else if(typeof XDomainRequest!='undefined'){xhr=new XDomainRequest();xhr.open(method,url);}else{xhr=null;}                 return xhr;}

4.实例

下面看个简单的例子,http://www.jsdemo.com/demoajax/demo3.htm 跨域请求 http://www.othersite.com/weather.ashx 中的数据。这是本地搭建的两个测试站点,demo源码见文章底部。

weather.ashx首先检测来源页面,然后决定是否返回Access-Control-Allow-Origin头。

public void ProcessRequest (HttpContext context) {context.Response.ContentType = "text/plain";string referrer = context.Request.ServerVariables["HTTP_REFERER"];if (!string .IsNullOrEmpty(referrer) && referrer.IndexOf( "http://www.jsdemo.com") > -1){context.Response.AddHeader( "Access-Control-Allow-Origin" , "http://www.jsdemo.com");}context.Response.Write( "{\"weather\": \"晴\",\"wind\": \"微风\"}" );}

demo3.htm通过CORS方式进行跨域请求,并将结果解析后显示在页面中。

var xhr=createCORSRequest("get","http://www.othersite.com/weather.ashx");xhr.οnlοad=function(){if(xhr.status==200||xhr.status==304){var result=xhr.responseText;var json=JSON.parse(result);var obj= document.getElementById("result");obj.innerHTML="天气:"+json.weather+";风力:"+json.wind;}}xhr.send();

四、图像跨域请求

<img>标签是没有跨域限制的,我们可以利用图像标签实现一种简单的、单向的跨域通信。图像ping通常用于跟踪用户点击数和广告曝光次数等。

特点:图像跨域请求只能用于浏览器和服务器之间的单向通信,它只能发送Get请求,而且服务访问服务器的响应内容。

来看个小例子demo4.htm,客户端点击链接时触发跨域请求。

<a href="javascript:void(0);" οnclick="Click()">点击我</a><script>function Click(){var img=new Image();img.οnlοad=function(){alert('DONE');}img.src="http://www.othersite.com/demo4.ashx?r="+Math.random();}</script>

服务端进行简单的计数,并且发送回一像素大小的图像。客户端接收到该结果后会弹窗提示“DONE”。

public static int Count=0;public void ProcessRequest (HttpContext context) {context.Response.ContentType = "text/plain" ;Count++;context.Response.ContentType = "image/gif" ;System.Drawing. Bitmap image = new System.Drawing. Bitmap(1, 1);image.Save(context.Response.OutputStream, System.Drawing.Imaging. ImageFormat .Gif);context.Response.Write(Count);}

五、JSONP跨域请求

1.JSONP结构

JSONP是很常用的一种跨域请求方案,常见的JSONP请求格式如下:

http://www.othersite.com/demo5.ashx?callback=showResult

响应结果看上去就像是包在函数调用中的JSON结构:

showResult({"weather": "晴","wind": "微风"})

JSONP结果由两部分组成:回调函数和数据。回调函数一般是在发起请求时指定的,当响应完成时会在页面中调用的函数;数据当然就是请求返回的JSON数据结果。

2.发起请求:

JSONP原理上是利用了动态<script>标签实现的,通过创建script对象,并且将其src属性设置为跨域请求的url地址。当请求完成后,JSONP响应加载到页面中便立即执行。

<script>function showResult(json){                var obj= document.getElementById("result");obj.innerHTML="天气:"+json.weather+";风力:"+json.wind;}var script=document.createElement("script");script.src="http://www.othersite.com/demo5.ashx?callback=showResult";document.body.insertBefore(script,document.body.firstChild);</script>

3.特点:

  • JSONP可以实现浏览器和服务器双向通信,并且能够访问响应中的文本;
  • JSONP是从其他域中加载代码并执行的,需要注意其安全性;
  • JSONP请求结果成败不易确定。

附件:DEMO源码

本文转自 陈敬(Cathy) 博客园博客,原文链接:http://www.cnblogs.com/janes/p/3968781.html,如需转载请自行联系原作者

读javascript高级程序设计15-Ajax,CORS,JSONP,Img Ping相关推荐

  1. 读javascript高级程序设计-目录

    javascript高级编程读书笔记系列,也是本砖头书.感觉js是一种很好上手的语言,不过本书细细读来发现了很多之前不了解的细节,受益良多.<br/> 本笔记是为了方便日后查阅,仅作学习交 ...

  2. 读javascript高级程序设计10-DOM

    一.节点关系 元素的childNodes属性来表示其所有子节点,它是一个NodeList对象,会随着DOM结构的变化动态变化. hasChildNodes():是否有子节点. var headline ...

  3. 读javascript高级程序设计11-事件

    一.事件流 事件流指从页面中接收事件的顺序. 1.事件冒泡(常用) IE中采用的事件流是事件冒泡,先从具体的接收元素,然后逐步向上传播到不具体的元素. 2.事件捕获(少用) Netscapte采用事件 ...

  4. 读javascript高级程序设计06-面向对象之继承

    原型链是实现继承的主要方法,通过原型能让一个引用类型继承另一个引用类型. 1.原型链实现继承 function SuperType(){ this.superprop=1; } SuperType.p ...

  5. 读javascript高级程序设计13-JSON

    JSON是一个轻量级的数据格式,可以简化表示数据结构的工作量.在实际工作中,我们经常用它来传递数据,不过对于其使用的一些细节还是需要注意的.在ECMAScript5中定义了原生的JSON对象,可以用来 ...

  6. 读javascript高级程序设计02-变量作用域

    一. 延长作用域链 有些语句可以在作用域前端临时增加一个变量对象,该变量对象在代码执行完成后会被移除. ①with语句延长作用域. function buildUrl(){ var qs=" ...

  7. 读javascript高级程序设计12-HTML5脚本编程

    一.跨文档消息传递(XDM) 1.发送消息 postMessage(msg,domain)用于发送跨文档消息.第一个参数是要传递的消息内容,第二个参数表示接收方来自哪个域.第二个参数有助于提高安全性, ...

  8. 读javascript高级程序设计03-函数表达式、闭包、私有变量

    一.函数声明和函数表达式 定义函数有两种方式:函数声明和函数表达式.它们之间一个重要的区别是函数提升. 1.函数声明会进行函数提升,所以函数调用在函数声明之前也不会报错: test(); functi ...

  9. 读javascript高级程序设计04-canvas

    一.基本用法 1.要使用canvas元素,需要先给定其width和height来设置绘图区域的大小.canvas中间的文本会在浏览器不支持canvas的情况下显示出来. <canvas widt ...

最新文章

  1. Hankson的趣味题 解题记录
  2. WSL2——Linux C中进程相关操作编程问题
  3. 如何将文件加添加成webapp
  4. python中的集合set
  5. 删除Ubuntu旧内核的几种方法,这下grub菜单看起来清爽多了!
  6. LARGE_INTEGER类型和QueryPerformanceFrequency()
  7. HDU1198-----并查集
  8. 【IoT】STM32 启动代码汇编指令详解
  9. 使用python破解zip、rar压缩包密码
  10. IC基础知识3-输入阻抗和输出阻抗
  11. 58.3万笔/秒!看阿里的黑科技
  12. 网络错误0x80070005,访问被拒绝[亲测解决]
  13. 完美解决Window11任务栏合并图标的问题。
  14. 静态html使用js发送邮件,科技常识:html实现邮箱发送邮件_js发送邮件至指定邮箱功能...
  15. Len和lenB的区别
  16. 大数据就业前景如何?马云曾经说过大数据是未来顶峰时代应验了
  17. unity 代码拷贝材质球
  18. ChatGPT大规模封锁亚洲地区账号
  19. Java web框架
  20. MySQL定时任务删除数据

热门文章

  1. StoryBoard布局注意事项
  2. gbdt 回归 特征重要性 排序_GBDT 理解
  3. uniapp启动页,底部虚拟按钮向上闪一下的问题
  4. AtCoder AGC002E Candy Piles (博弈论)
  5. ZBrush关于遮罩的一些操作
  6. ThreadLocal的使用及原理分析
  7. 【margin和padding的区别】
  8. 《C语言及程序设计》实践參考——分数的累加
  9. C# + ArcEngine 常用方法(不定时更新)
  10. windows配置nginx实现负载均衡集群