jQuery代码分析之五Ajax调用

来源:互联网 发布:股票数据转换 编辑:程序博客网 时间:2024/05/01 08:51

在stackoverflow上看到一个问题,用jQuery.get()跨域(cross domain)访问google api在IE(8,9)中行不通,最后,解决方案是用一个jQuery的ajax扩展,技术要点是应用了IE8,9中特有的XDomainRequest对象,这是它所独有的,不遵循任何当前标准。在后面我们还会提到,IE在做ajax调用时也是有它自己独特的方式。

在jQuery文档中关于Ajax api的应用大体可以分为两部分,参数设置和事件绑定。

必选参数

>url - 要请求的url地址

可选参数

怎样制定默认值?可以通过jQuery.ajaxSetup()来指定

accepts - 默认值依赖于DataType(下面会提到),用于请求告诉服务器它期待什么样的响应

async - 默认值是true,跨域请求和jsonp类型的请求不支持同步方式发起请求

cache - 当dataType为script或jsonp时默认值为false,否则默认值为true,当cache为true时,会在请求消息头(request header)里插入一项_={timestamp}

contents - 字符串/正则表达式的名值对,用于知道jQuery怎么解析响应(response)

contentType - 默认值是‘application/x-www-form-urlencoded; charset=UTF-8

context - 当ajax过程中的回调函数被调用时的上下文,默认值是$.ajaxSettings与$.ajax()传入的options融合后的结果

converts - datatype到datatype的转换函数,默认值是{"* text": window.String, "text html": true, "text json": jQuery.parseJSON, "text xml": jQuery.parseXML},例如把任何datatype转换为text用window.String

crossDomain - 默认值为false,如果是跨域请求则设为true

data - 传递到server端的参数,如果它的数据类型不是string,那它会被转换为querystring,然后插入到url后面,这样子的话就要求它是名值对的对象,但是它如果是数组类型时,怎么办呢?

dataType - 期待从server端返回的数据类型,可以是xml,json,script,html。如果没有指定的话,jQuery会根据响应流的MIME类型自动推导。可供选择的dataType还有jsonp,text。另外我们也可以通过一组用空格分开的字符串来把响应流变成我们期待的类型,例如,我们有一个jsonp的调用,它本来返回的是text,然后我们把它翻译成xml,这个时候我们可以设定dataType为"jsonp text xml"。

global - 默认值是true,设定global ajax event handler例如ajaxStart,ajaxStop是否被调用

headers - 名值对表示请求中额外的消息头内容

ifModified - 默认值是false,检查响应流的Last-Modified消息头,如果ifModified是true,那么请求只有当response的Last-Modified消息头改变时才算成功

isLocal - 请求的资源是否在本地

jsonp

jsonpCallback

mimeType

password

processData - 默认值是true,任何非string类型的数据都要被转换然后插入querystring,然后使之适应默认的content-type“application/x-www-form-urlencoded”

scriptCharset - 只有当请求script时才有用,可以在请求的script所在的tag设置charset,例如

<script type="text/javascript" charset="utf-8">// 发起ajax请求的代码...</script>

timout

tranditional

type

url

username

xhr - 创建XMLHttpRequest对象的方法

xhrFields - 可以直接设置xhr返回对象的属性值

事件回调函数

beforeSend

error

dataFilter

success

complete

注意从jQuery1.8开始,xhr实现了promise接口,以前定义的success,fail,complete分别被promise接口里的done,fail,always取代了。

global ajax event handler

为啥叫global呢?我想大概是因为受options中global变量的控制吧(上文提到过global变量设置哦)。这些回调函数只有当global为true时才会被调用。特别地,对于jsonp和跨域请求,不管global的值是啥都不会调用这些全局ajax回调函数。这些函数都不是jquery的全局函数,而是jQuery元素上的方法。另外,因为当这些事件发生时,只要监听了它的jQuery元素都会被通知,所以从这个角度来说也是全局的。与ajaxSetting中的回调函数相对,ajaxSetting中的回调函数只针对当前ajax请求,也可以称这些为局部的(local)。

ajaxStart

当页面中第一个ajax请求发出时被触发

ajaxSend

ajaxComplete

ajaxError

从1.8起,ajaxError只能在document上调用。

ajaxSuccess

ajaxStop

当处理完最后一个ajax请求时被触发


看到这么多参数设置,我想很多人跟我一样都很晕,那么,jQuery也提供了一些套餐方法,

jQuery.get()

jQuery.post()

$.get()和$.post()的实现完全一样,只是参数type不一样,一个是GET,一个是POST

jQuery.getJSON()

jQuery.getScript()

文档中$.get()的完整定义其实是$.get(url [,data] [,success(data,textStatus,jqXHR)] [,dataType])。

$.getJSON()只是调用$.get(),只不过最后一个参数dataType传递的是“json”。$.getScript只是调用$.get(),其最后一个参数dataType传递的是"script"。注意,$.getScript没有参数data。

fn.load()

load()方法不是在$全局命名空间中的,而是jQuery元素上的方法,用于把ajax请求的结果直接应用在调用元素上,换句话说就是,ajax过程中触发的回调函数的执行上下文(context)就是调用元素。特别地,如果response是一个DOM结构,它还可以在请求url中制定CSS选择子,来过滤所需要的DOM元素。例如,

$("#loadTest").load("NewFile.html p", function(responseText, textStatus, XMLHttpRequest) {        console.log(responseText);    });
它会获取页面NewFile.html中document下所有的p元素,然后把它们插入调用元素中。有一点要提到,如果被请求url中没有选择子,那么被请求页面中的脚本可以被执行,如果请求url中添加了选择子,那么被请求页面中的脚本不可以被执行。

XSS

same origin policy 同源策略,是浏览器用于控制资源访问安全的一种方式。它要求一个页面只能访问与该页面同源的资源。同源基于3个比较标准,应用协议,域名,端口号。只有这三项同时相等才能认为是同源的。注意,在url中的资源路径并不在比较之内。另外有种情况要特别强调,浏览器在比较时是用域名进行字符串比较,比如http://example.com与http://192.168.0.123,就算example.com的IP地址就是192.168.0.123,它们也不被认为是同源。

跨域请求的解决方案

  1. 在web服务器端用服务器端脚本访问非同源资源然后返回,这样客户端向web服务器发起同源请求,但是web服务器负责请求非同源资源,这个时候同源策略对web服务器是没有限制的。
  2. JSONP - JSON with Padding HTML标签script可以执行非同源脚本,比如我们常用的jQuery CDN。利用这个特性,我们可以让服务器端的service返回一段JavaScript脚本,为了增强交互性,我们可以让这个service也支持传入一个本地回调函数。当请求得到响应后,用返回的JavaScript脚本新建一个script tag然后插入当前页面。从请求返回到浏览器之后的过程都已经由jQuery实现了。所以用jQuery做JSONP请求时就很简单了,只要制定dataType为jsonp,然后指定一个回调函数。jQuery在发起jsonp请求时,实际上还是用的HTTP GET,只不过在处理响应时做了一些额外的操作。
  3. CORS - Cross-Origin Resource Share 这种做法已经被W3C标准化了。服务器在返回响应时可以插入名叫Access-Control-Allow-Origin的消息头,用于指定什么样的源可以获取该资源,如果浏览器发现请求发起的源并不在此列,那就对该请求返回ERROR 404。如果服务器不想对访问该资源的请求不作任何限制,那么可以指定Access-Control-Allow-Origin的值为*。当然这个标准在当前主流浏览器中的实现情况有些差异:FireFox/Chrome一般不会有什么问题,除非你用那种很早期的版本(比如3或之前);IE在8/9中是用一个叫XDomainRequest的对象实现,只有在最新的IE10中才支持这个标准。其它的IE版本就完全不支持了。