zoukankan      html  css  js  c++  java
  • 《JavaScript高级程序设计》学习笔记——XML、Ajax

    Author:chemandy

    第十五章 JavaScript与XML

    1.浏览器对XML DOM的支持

    1.1 DOM2级核心

    ①在DOM2级在document.implementation中引入了createDocument()方法(IE6~8不支持)。

    可以创建一个空白XML。

    var xmldom = document.implemention.createDocument(namespaceUri,root,docype);

    ②要创建一个新的文档元素为<root>的XML文档,可用如下代码:

    var xmldom = document.implementation.createDocument("","root",null);

    aert(xmldom.documentElement.tagName);  //"root"

    var child = xmldom.createElement("child");

    xmldom.documentElement.appendChild(child);

    ③检测浏览器是否支持DOM2级XML:

    var hasXmlDom = document.implementation.hasFeature("XML","2.0");

    1.2 DOMParse类型

    ①Firefox、Opera、Chrome、Safari支持(IE8不支持),DOMParse类型可将XML解析为DOM文档。

    ②创建一个DOMParse实例,再调用parseFromString()方法。这个方法接受两个参数:要解析的XML字符串和内容类型(内容类型始终为"text/xml")。返回值是一个Document实例。

    var parser = new DOMParse();

    var xmldom = parser.parseFromString("<root><child/></root>","text/xml");

    alert(xmldom.documentElement.tagName);  //"root"

    alert(xmldom.documentElement.firstChild.tagName);  //"child"

    var anotherChild = xmldom.createElement("child");

    xmldom.documentElement.appendChild(anthorChild);

    var children = xmldom.getElementsByTagName("child");

    alert(children.length);  //2

    ③发生解析错误时,仍然会从parseFromString()中返回一个Document对象。但这个对象的文档元素是<parsererror>(Firefox、Opera);对象根元素第一个子元素为<parsererro>(Safari、Chrome)。

    <parseerror>元素的内容是对解析错误地描述。通过getElementsByTagName()查找<parsererror>确定是否有解析错误。

    var parse = new DOMParse();

    var xmldom = parser.parseFromString("<root>","text/xml");

    var errors = xmldom.getElementsByTagName("parsererror");

    if(errors.length > 0 ){

    alert("Parsing error!");

    }

    1.3 XMLSerializer类型

    ①此类可将DOM文档序列化为XML字符串。(IE6~8不支持)。

    ②要序列化DOM文档,首相必须创建XMLSerializer实例,然后将文档传入其serializerToString()方法:

    var serializer = new XMLSerializer();

    var xml = serializer.serializeToString(xmldom);

    alert(xml);

    1.4 DOM3级加载和保存

    ①DOM3级“加载和保存”规范的目的在于将加载、解析和序列化XML文档的任务标准化,模块规定了两个解析方法:同步方法和异步方法。

    ②检测DOM3级加载和保存

    var hasLSSync = document.implementation.hasFeature("LS","3.0");

    var hasLSAsync = document.implementation.hasFeature("LS-Async","3.0");

    ③DOM3级“加载和保存”还为document.implementation对象添加了下列新属性和新方法:

    □MODE_SYNCHRONOUS:为同步解析方式定义的常量;

    □MODE_ASYNCHRONOUS:为异步解析方式定义的常量;

    □createLSParse(mode,schemaType):创建一个在指定方式(mode)下运行且符合指定模式(schema)类型的解析器。

    □createLSSerializer():创建一个新XML序列化器。

    □createLSInput():创建一个新的输入对象,用于解析/序列化操作。

    □createLSOutput():创建一个新的输出对象,用于解析/序列化操作。

    1.4.1 解析XML

    (1)同步解析器

    ①需要先创建同步解析器。如果解析器并不想基于哪个模式进行验证,为createLSParser()的第二个参数传入null。如果需要基于XML模式进行验证,则应为第二个参数传入"http://www.w3.org/2001/XMLSchema",如果要基于XML DTD进行验证,则应该为第二个参数传入"http://www.w3.org/TR/REC-xml"。

    ②解析之前还要创建一个新的LSInput对象。为此,要使用createLSInput()方法;创建LSInput对象后,还需要将XML字符串赋值给该对象的stringData属性。

    ③解析完成后,就会返回一个XML DOM文档对象

    ④如果在同步解析方式下发生解析错误,则会抛出错误。

    ⑤示例:

    var implementation = document.implementation;

    var parser = implementation.createLSParser(implementation.MODE_SYNCHRONOUS,null);

    var input = implement.createLSInput();

    input.stirngData = "<root>";

    try{

    xmldom = parser.parse(input);

    }catch(ex){

    alert("Parsing error!");

    }

    (2)异步解析器

    ①需要在createLSParser()的第一个参数的位置上传入常量MODE_ASYNCHRONOUS。

    ②通过addEventListener()来预订load事件,以便知道文档何时解析完毕。

    ③如果异步解析期间发生错误,则不会触发load事件。要捕获这个错误,需要使用LSParser对象上一个名叫domConfig的特殊接口定义一个错误处理程序。(BUG:Opera9.5不会触发load)

    ④domConfig为DOMConfiguration类型的实例,表示针对特定文档的解析和格式化规则。LSParser会用此对象指定额外配置信息,需调用setParameter()方法。其中一个参数是"error_handler",用于指定处理解析错误的函数。

    var implementation = document.implementation;

    var parser = implementation.createLSParser(implementation.MODE_ASYNCHROUNS,null);

    var input = implementation.createLSInput();

    input.stringData = "<root>";

    //预订load事件,但不会触发load事件

    parser.addEventListener("load",function(event){

    var xmldom = event.newDocument;

    var input = event.input;

    alert(xmldom.documentElement.tagName); //"root"

    alert(xmldom.documentElement.firstChild.tagName);  //"child"

    var anotherChild = xmldom.createElement("child");

    xmldom.documentElement.appendChild(anotherChild);

    var children = xmldom.getElementsByTagName("child");

    alert(children.length);  //2

    },false);

    parser.domConfig.setParameter("error_handler",fucntion(ex){

    alert("Parsing error!");

    });

    //开始解析

    parser.parse(input);

    1.4.2 其它解析方式

    通过LSParser还可以执行两种类型的解析:解析来自URI的文件和基于上下文解析。

    (1)解析来自URI的XML。

    ①不用创建LSInput。

    ②开始解析时调用parseURI()方法,并为其传入一个指向有效XML的URI。Parser.parseURI("example.xml");

    (2)基于上下文解析

    ①首先解析字符串,然后将解析结果插入另一个文档。

    ②使用parseWithContext()方法接受3个参数:LSInput对象、上下文节点和要执行的操作。

    □LSInput对象的stringData属性中必须包含XML片段的代码,不能含有XML序言内容(prolog)。

    □上下文节点是解析完的片段该插入的地方。

    □要执行的操作必须是下列LSParser常量之一。

    ◇ACTION_APPEND_AS_CHILDERN:将解析结果作为子节点添加到上下文节点中。

    ◇ACTION_REPLACE_CHILDREN:先移除上下文节点的所有节点,然后将解析结果作为上下文节点的子节点插入。

    ◇ACTION_INSERT_BEFORE:将解析结果作为上下文节点的同辈节点,插入到上下文节点前面。

    ◇ACTION_INSERT_AFTER:将解析结果作为上下文节点的同辈节点,插入到上下文节点后面。

    ◇ACTION_REPLACE:用解析结果替换上下文节点。

    ◇在解析错误时,以上操作均会被取消。

    var implementation = document.implement;

    var parser = implementation.createLSPareser(implementation.MODE.SYNCHRONOUS,null);

    var input = implementation.createLSInput();

    input.stringData = "<root/>";

    var xmldom = parser.parse(input);

    var newInput = implementation.createLSInput();

    newInput.StringData = "<child/>";

    parse.parseWithContext(newInput,xmldom.documentElement,parser.ACTION_APPEND_AS_CHILDREN);

    alert(xmldom.documentElement.firstChild.tagName);  //"child"

    1.4.3 序列化XML

    ①要调用document.implementation上的createLSSerialization()方法,创建一个LSSerializer对象。LSSerializer对象的主要方法是writeToString(),接受一个节点类型参数并返回该节点的XML代码字符串表述。

    ②通过LSSerializer对象的domCOnfig属性来设置适合打印输出的XML字符串格式,即将该属性的"format_pretty_print"参数设为true。

    ③序列化期间发生错误,错误会被抛出。通过将writeToStirng()放try-catch语句中,可以测试是否发生了错误。

    var serializer = implementation.createLSSerializer();

    serializer.domConfig.setParameter("format_pretty_print",true);

    var xml = "";

    try{

    Xml = serializer.writeToString(xmldom);

    }catch(ex){

    Alert("Serialization error occurred");

    }

    alert(xml);

    1.5 IE对XML的支持

    ①IE有6种不同的XML文档版本可供选择,只建议其中3种:

    □MSXML2.DOMDocument:为方便脚本处理而更新的版本,建议仅在特殊情况下作后备版本使用。

    □MSXML2.DOMDocument.3.0:为了在JavaScript中使用,这是最低的建议版本。

    □MSXML2.DOMDocument.6.0:通过脚本能够可靠地处理的最新版本。

    □确定可用版本:

    function createDocument(){

    if(typeof arguments.callee.activeXString ! = "string"){

    var versions = ["MSXML2.DOMDocument.6.0","MSXML2.DOMDocument.3.0","MSXML2.DOMDocument"];

    for(var i = 0, len = versions.length; i < len; i++){

    try{

    var xmldom = new ActiveXObject(versions[i]);

    arguments.callee.activeXString = versions[i];

    return xmldom;

    }catch(ex){

    //跳过

    }

    }

    }

    return new ActiveXObject(arguments.callee.activeXString);

    }

    ②要解析XML字符串,先创建XML DOM文档,然后调用其loadXML()方法。

    var xmldom = createDocument();

    xmldom.loadXML("<root><child/></root>");

    □在新DOM文档中填充了XML内容后,就可以像操作其他DOM文档一样操作它了(可以使用任何方法和属性)

    ③如果解析过程中出错,可以在parseError属性对象中找到错误。包含多个保存错误信息的属性。

    □errorCode:错误类型的数值编码;没有发生错误时值为0

    □filePos:文件中导致错误发生的位置。

    □line:发生错误的行。

    □linepos:发生错误的行中的字符。

    □reason:对象错误地文本解析。

    □srcText:导致错误的代码。

    □url:导致错误的文件的URL。

    □parseError的valueof()方法返回errorCode的值。

    if(xmldom.parseError != 0){

    alert("An error occurred: \n Error Code:"+xmldom.parseError.errorCoed + "\n" 

    + "line:" + xmldom.parseError.line + "\n"

    + "line.Pos" + xmldom.parseError.linepos + "\n"

    + "Reson:" + xmldom.parseError.reason

    );

    }

    1.5.1序列化XML

    IE序列化XML的能力内置在了XML DOM文档中。每个XML DOM节点都有一个xml属性,其中保存着表示该节点的XML字符串。alert(xmldom.xml)

    1.5.2 加载XML文件

    ①与DOM3级功能类似,要加载的XML文档必须与JS代码来自同一服务器。

    ②加载文档的方式也可以分为同步和异步两种。要指定加载文档的方式,可以设置async属性,true表示异步(默认),false表示同步。使用load(URI)方式加载。

    ③异步加载XML,需为XML DOM文档的onreadystatechange事件指定处理程序。有4个就绪状态(ready state)

    □1:DOM正在加载数据。

    □2:DOM已经加载完数据。

    □3:DOM已经可以使用,但某些部分可能还无法访问。

    □4:DOM已经完全可以使用。

    □实际上,只需要关注状态4。通过XML文档的readyState属性可得其就绪状态。

    var xmldom = createDocument();

    xmldom.async = true;

    xmldom.onreadystatechange = function(){

    if(xmldom.readyState == 4){

    if(xmldom.parseError != 0){

    Alert("An error occurred");

    }else{

    //其他xmldom操作

    }

    }

    }

    xmldom.load("exmaple.xml");

    注:

    □onreadystatechange事件指定处理语句须在调用load()方法之前。

    □在事件处理内部由于ActiveX控件为预防错误,不允许使用this。

    1.6 跨浏览器处理XML

    function parseXML(xml){

    var xmldom = null;

    if(typeof DOMParser != "undefined"){

    xmldom = (new DOMParser()).parseFromString(xml,"text/xml");

    var errors = xmldom.getElementsByTagName("parsererror");

    if(errors.length){

    throw new Error("XML parsing error:" + errors[0].textContent);

    }

    }else if(document.implementation.hasFeature("LS","3.0")){

    var implementation = document.implementation;

    var parser = implementation.createLSParser(implementation.MODE_SYNCHRONOUNS,null);

    var input = implementation.createLSInput();

    input.stringData = xml;

    xmldom = parser.parse(input);

    }else if(typeof ActiveXObject != "undefined"){

    xmldom = createDocument();

    xmldom.loadXML(xml);

    if(xmldom.parseError != 0){

    throw new Error("XML parsing error:" + xmldom.parseError.reason);

    }

    }else{

    throw new Error("No XML parser available.");

    }

    return xmldom;

    }

    用此函数解析XML字符串时,应该放在try-catch语句中

    var xmldom = null;

    try{

    xmldom = parseXml("<root><child/><root>");

    }

    catch(ex){

    alert(ex.message);

    }

    ■序列化XML兼容代码

    function serializeXml(xmldom){

    if(typeof XMLSerializer != "undefined"){

    return(new XMLSerializer()).serializeToString(xmldom);

    }else if(document.implementation.hasFeature("LS","3.0")){

    var implementation = document.implementation;

    var serializer = implemetation.createLSSerializer();

    return serializer.writeToString(xmldom);

    }else if(typeof xmldom.xml != "undefined"){

    return xmldom.xml;

    }else{

    throw new Error("Could not serialize XMLDOM.");

    }

    }

    2.浏览器对XPath的支持

    2.1 DOM3级Xpath

    ①DOM3级支持XPath,检测浏览器支持:

    Var supportsXPath = document.implementation.hasFeature("XPath","3.0");

    ②DOM3级XPath中最重要的两个类型:XPathEvaluator和XPathResult。

    ③XPathEvalutor用于特定的上下文中队XPath表达式求值。有3个方法:

    □createExpression(expression,nsresolver):将XPath表达式及相应的命名空间信息转换成一个XPathExpression,这是查询的编译版。在多次使用一个查询时很有用。

    □createNSResolver(node):根据node的命名空间信息创建一个新的XPathNSResolver对象。在基于使用命名空间的XML文档求值时,需要使用XPathNSResolver对象。

    □evaluate(expression,context,nsresolver,type,result):在给定的上下文中,基于特定的命名空间信息来对XPath表达式求值。剩下的参数表示如何返回结果。

    □在支持DOM3级的浏览器中,Document类型通常都是与XPathEvaluator接口一起实现的。

    ④上面3个方法中,evalute最常用。接受5个参数:

    □XPath表达式

    □上下文节点

    □命名空间解析器(只在XML代码中使用了XML命名空间时有必要指定,否则为null)

    □返回结果的类型(见书P415)

    □保存结果的XPathResult对象(通常是null,因为结果也会以函数值形式返回)

    ■返回结果类型为以下的其中一个:

    ◇XPathResult.ANY_TYPE

    ◇XPathResult.NUMBER_TYPE

    ◇XPathResult.STRING_TYPE

    ◇XPathResult.BOULEAN_TYPE

    ◇XPathResult.UNORDER_NODE_ITERATOR_TYPE

    ◇XPathResult.ORDERED_NODE_SNAPSHOT_TYPE

    ◇XPathResult.ANY_UNORDERED_NODE_TYPE

    ◇XPathResult.FIRST_ORDERED_NODE_TYPE

    1)指定的是迭代器结果,须用iterateNext()方法从节点中取得匹配节点,无则返回null。

    var result = xmldom.evalute("employee/name",xmldom.document,null,XPathResult.ORDERED_NODE_ITERATOR_TYPE,null);

    if(result !== null){

    var node = result.iterateNext();

    while(node){

    alert(node.tagName);

    node = node.iterateNext();

    }

    }

    2)指定的是快照类型,就必须使用snapshotItem()和snapshotLength属性。

    1.单节点结果

    指定常量XPathResult.FIRST_ORDER_NODE.TYPE会返回第一个匹配节点,可通过singleNodeValue属性来访问该节点。

    2.简单类型结果

    booleanValue、numberValue和stringValue

    3.默认类型结果

    4.命名空间支持

    □对于利用了命名空间的XML文档,XPathEvaluator必须知道命名信息,然后才能正确地进行求值。

    □第一种方法是通过createNSResolver()来创建XPathNSResolver对象,这个方法接受一个参数,即文档中包含命名空间定义的节点。

    Var nsresolver = xmldom.createNSResolver(xmldom.documentElement);

    Var result = xmldom.evaluate("wrox:book/wrox:author",xmldom.document,nsresolver,XPathResult.ORDERED_NODESNAPSHOTTYPE,null);

    Alert(result.snapshotlength);

    □第二种方法是定义一个函数,让它接受一个命名空间前缀,返回关联的URI。

    Var nsresolver = function(prefix){

    Switch(prefix){

    Case "wrox" : return "http://www.wrox.com/";

    //其他前缀

    }

    };

    Var result = xmldom.evaluate("count(wrox:book/wrox:author)",xmldom.document,nsresolver,XPathResult.NUMBER_TYPE,null);

    2.2 IE中的XPath

    ①IE对XPath的支持是内置在XML DOM文档对象中的。含有两个方法。

    □selectSingleNode()方法接受一个XPath模式,在找到匹配节点时返回第一个匹配的节点。

    var element = xmldom.documentElement.selectSingleNode("employee/name");

    □selectNodes(),接受一个XPath模式作参数,返回与模式匹配的所有节点的NodeList(如果没有匹配的节点,则返回一个包含零项的NoedList)。

    Var elements = xmldom.documentElement.selectNodes("employee/name");

    Alert(elements.length);

    ②IE对命名空间的支持

    □必须知道自己使用的命名空间,并按格式创建一个字符串:

    "xmlns:prefix1 = 'uri1' xmlns:prefixf2 = 'uri2' xmlns:prefix3:'uri3' "

    □将上述格式字符串传入到XML DOM文档对象的特殊方法setProperty()中。

    □setProperty()接受两个参数:要设置的属性名和属性值。这里属性名应为"SelectionNameSpaces",属性值是前面格式的字符串。

    xmldom.setProperty("selectionNameSpaces","xmlns:wrox = http://www.wrox.com");

    var result = xmldom.documentElement.selectNodes("wrox:book/wrox:author");

    2.3 跨浏览器使用XPath

    □selectSingleNode()函数兼容代码

    function selectSingleNode(context,expression,namespace){

    var doc = (context.nodeType != 9 ? context.ownerDocument : context);

    if(typeof doc.evaluate != "undefined"){

    var nsresolver = null;

    if(namespace instanceof Object){

    nsresolver = fucntion(prefix){

    return namespaces[prefix];

    };

    }

    var result = doc.evaluate(expression,context,nsresolver,XPathResult.FIRST_ORDERED_NODE_TYPE,null);

    return(result !== null ? Result.singleNodeValue : null);

    }else if(typeof context.selectSingleNode != "undefined"){

    //创建命名空间字符串

    if(namespaces instanceof Object){

    var ns = "";

    for(var prefix in namespaces){

    if(namespaces.hasOwnproperty(prefix)){

    ns += "xmlns:" + prefix + "='" + namespaces[prefix] + "' ";

    }

    }

    doc.setProperty("SelectionNamespaces",ns);

    }

    return context.selectSingleNode(expression);

    }else{

    throw new Error("No Xpath engine found.");

    }

    }

    □selectNodes()函数兼容代码

    P420略

    3.函数对XSLT的支持

    XSLT是与XML相关的一种技术,它利用XPath将文档从一种表现形式转换成另一种表现形式。

    3.1 IE中的XSLT转换

    1.简单的XSLT转换

    □最简单方法:XSLT、XML分别加载到一个DOM文档中,再使用transformNode()方法。

    □transformNode()方法:只有一个参数——包含XSLT样式表的文档。返回一个包含转换信息的字符串。

    □可在xmldom各个节点机型转换。

    //加载xmldom各个节点进行转换

    xmldom.load("employees.xml");

    xsltdom.load("employees.xslt");

    //转换

    var result = xmldom.transformNode(xsltdom);

    2.复杂的XSLT转换

    ①基本原理:

    a.将xml加载到“线程安全的XML DOM”中。

    b.将XSLT加载到“XSL模板”中

    c.使用“XSL处理器”进行转换。

    □自由线程DOM:MSXML2.FreeThreadedDOMDocument

    □XSL模板:MSXML2.XSLTemplate

    □XSL处理器:调用XSL模板的createProcessor()创建XSL处理器。

    ②把XSLT样式表加载到一个线程安全的XML文档中。

    function createThreadSafeDocument(){

    if(typeof arguments.callee.activeXString != "string"){

    var versions = ["MSXML2.FreeThreadedDOMDocument.6.0","MSXML2.FreeThreadedDOMDocument.3.0","MSXML2.FreeThreadedDOMDocument\"];

    for(var i=0,len = version.length; i<len; i++){

    try{

    var xmldom = new ActiveXObject(versions[i]);

    arguments.callee.activeXString = versions[i];

    return xmldom;

    }catch(ex){

    // 跳过

    }

    }

    }

    return new ActiveXObject(arguments.callee.activeXString);

    }

    □线程安全的XML DOM与常规XML DOM使用方式一致。

    var xsltdom = createThreadSafeDocument();

    xsltdom.async = fasle;

    xsltdom.load("employee.xslt");

    ③为自由线程DOM指定XSL模板

    fucntion createXSLTemplate(){

    if(typeof arugments.callee.activeXString != "string"){

    var versions = ["MSXML2.XSLTemplate.6.0","MSXML2.XSLTemplate.3.0","MSXML2.XSLTemplate"];

    for(var i=0,len=versions.length;i<len;i++){

    try{

    var template = new ActiveXObject(versions[i]);

    arguments.callee.activeXString = version[i];

    return template;

    }catch(ex){

    //跳过

    }

    }

    }

    return new ActiveXObject(arguments.callee.activeXString);

    }

    □使用createXSLTemplate()函数创建用法:

    var template = createXSLTemplate();

    template.stylesheet = xsltdom;

    var processor = template.createProcessor();

    processor.input = xmldom;

    processor.transform();

    var result = processor.output;

    ④创建XSL处理器之后,须将要转换的节点指定给input属性。然后,调用transform()方法执行转换并将结果左字符串保存在output属性中。

    ⑤使用XSL处理器可以对转换进行更多的控制,同时也支持更高级的XSLT特性。

    □addParameter():两个参数:要设置的参数名称(与在<xsl:param>的name特性中给指定的一样)和要指定的值(多数是字符串,也可以是数值或布尔值)。

    □setStartMode():接受一个参数,即要为处理器设置的模式。

    □reset():重置处理器,清除原先的输入和输出属性、启动模式及其它指定的参数。processor.reset();

    3.2 XSLTProcessor类型(非IE浏览器支持)

    ①基本原理:

    a.加载两个DOM文档,一个基于XML,另一个基于XSLT。

    b.创建一个新XSLTProcessor对象

    c.使用importStylesheet()方法指定一个XSLT

    d.最后使用transformToDocument()或transfromToFragment()方法可得一个文档片段对象。

    var processor = new XSLTProcessor();

    processor.importStylesheet(xsltdom);

    □transformToDocument():只要传入XML DOM,就可将结果作为一个完全不同的DOM文档使用。

    □transformToFragement():两个参数:要转换的XML DOM和应该拥有结果片段的文档

    var fragment = processor.transformToDocument(xmldom,document);

    ②使用参数:

    □setParameter():3个参数:命名空间URI(一般为null)、参数内部名称和要设置的值

    □getParameter():取得当前参数的值,两个参数:命名空间和参数内部名。

    □removeParameter():移除当前参数的值,两个参数:命名空间和参数内部名。

    ③重置处理器

    □reset()方法:从处理器中移除所有参数和样式表。

    3.3 跨浏览器使用XSLT

    IE对XSLT转换支持与XSLTProcessor区别太大,跨浏览器兼容性最好的XSLT转换技术,只能是返回结果字符串。

    function transform(context,xslt){

    if(typeof XSLTProcess != "undefined"){

    var processor = new XSLTProcessor();

    processor.importStylesheet(xslt);

    var result = processor.transfromToDocument(context);

    return(new XMLSerialize()).serializeToString(result);

    }else if(typeof context.transforamNode != "undefined"){

    return context.transformNode(xslt);

    }else{

    throw new Error("No XSLT processor available.");

    }

    }

    第十六章 E4X (略)

    第十七章 Ajax与JSON

    1.XHR对象

    ①IE6需要使用MSXML库中的一个ActiveX对象实现,而其他浏览器原生支持XHR对象。

    function createXHR(){

    if(typeof XMLHttpRequest != "undefined"){

    return new XMLHttpRequest();

    }else if(typeof ActiveXobject != "undefined"){

    if(typeof arguments.callee.activeXString != "string"){

    var versions = ["MSXML2.XMLHttp.6.0","MSXML2.XMLHttp.3.0","MSXML2.XMLHttp"];

    for(var i=0, len = versions.length; I <len; i++){

    try{

    var xhr = new ActiveXObject(versions[i]);

    Arguments.callee.activeXString = versions[i];

    return xhr;

    }catch(ex){

    //跳过

    }

    }

    }

    return new ActiveXObject(arguments.callee.activeXString);

    }else{

    throw new Error("No XHR object available");

    }

    }

    1.1 XHR的用法

    ①open()方法

    □接受3个参数:要发送的请求的类型(“get”、“post”等)、请求的URL和表示是异步发送请求的布尔值。

    □参数URL是相对于执行代码的当前页面(当然也可以使用绝对路径);

    □调用open()方法并不会真正发送请求,而只是启动一个请求以备发送。

    ②send()方法

    □要发送特定的请求,必须使用send()方法启动。

    □接受一个参数,即要作为请求主体发送的数据。如果不需要通过请求主体发送数据,则必须传入null,因为这个参数对有些浏览器来说是必须的。

    □调用send()之后,请求就会被分派到服务器。

    ③相应的数据会自动填充XHR对象的属性,相关的属性简介如下:

    □responseText:作为相应主体被返回的文本。

    □responseXML:如果响应的内容是“text/xml”或“application/xml”,这个属性中将保存含着响应数据的XML DOM文档。

    □status:响应的HTTP状态。

    □statusText:HTTP状态的说明。

    ④处理响应的判断

    □检查status属性,以确定响应成功返回。

    □HTTP状态代码为200是成功的标志,此时responseText、responseXML应能访问。

    □HTTP状态代码为304表示请求的资源没修改,可使用缓存值。

    ⑤同步请求

    xhr.open("get", "example.txt", false);

    xhr.send(null);

    if( (xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){

    alert(xhr.statusText);

    }else{

    alert("Request was unsuccessful:" + xhr.status);

    }

    ⑥异步请求

    1)发送异步请求还需要检测XHR对象的readyState属性,该属性表示请求/响应过程的当前活动阶段。取值如下:

    □0:未初始化。尚未调用open()方法。

    □1:启动。已调用open()方法,未调用send()方法。

    □2:发送。已调用send()方法,但尚未接收到响应。

    □3:接收。已接收到部分响应数据。

    □4:完成。已经接收到全部响应数据,而且已经可以在客户端使用了。

    2)readyState值的变化会触发readyStatechange事件。由于并非所有浏览器支持DOM2级方法,因此用DOM0级添加处理程序。

    var xhr = createXHR();

    xhr.onreadystatechange = function(){

    if(xhr.readyState == 4){

    if( (xhr.staus >= 200 && xhr.status < 300) || xhr.status == 304){

    alert(xhr.responseText);

    }else{

    alert("Request was unsuccessful: " + xhr.status);

    }

    }

    };

    xhr.open("get","example.txt", true);

    xhr.send(null);

    ⑦在接收到响应之前还可以调用abort()方法取消异步请求。xhr.abort();

    1.2 HTTP头部信息

    XHR对象提供了操作“请求头部”和“响应头部”信息的方法。

    ①请求头部

    1)请求头部信息

    □Accept:浏览器能够处理的内容类型。

    □Accept-Charset:浏览器能够显示的字符集。

    □Accept-Encoding:浏览器能够处理的压缩编码。

    □connection:浏览器与服务器之间连接的类型。

    □Cookie:当前页面设置的任何cookie。

    □Host:发出请求的页面所在的域。

    □Referer:发出请求的页面的URI。

    □User-Agent:浏览器的用户代理字符串。

    ②setRequestHeader()方法可以设置自定义的请求头部信息。

    □接收两个参数:头部字段名称和头部字段的值。

    □要成功发送请求头部信息,必须在调用open()方法之后且调用send()方法之前。

    ③getResponseHeader()方法,传入头部字段名称,可以取得相应的响应头部信息。

    ④getAllResponseHeader()方法,取得一个包含所有头部信息的长字符串。

    1.3 GET请求

    ①常用语服务器查询信息。

    ②GET请求经常会发生查询字符串格式问题。查询字符串中每个参数的名称和值都必须使用encodeURIComponent()进行编码。

    ③辅助向现有URL末尾添加查询字符串参数:

    function addURLParam(url, name, value){

    url += (url.indexOf("?") == -1 ? "?" : "&" );

    url += encodeURIComponent(name) + "=" + encodeURIComponent(value);

    return url;

    }

    1.4 POST请求

    ①通常用于向服务器发送应该被保存的数据。

    ②xhr.open("post","example.php",true);发送post请求的第二步就是向send方法中传入某些数据。

    1.5浏览器差异

    ①IE

    □IE为XHR对象添加了一个timeout属性,表示请求在等待响应。

    □规定时间内没有接收到响应,就出发timeout事件,进而调用ontimeout事件处理程序。

    ②Firefox

    1)load事件

    2)progress事件

    2.跨域请求

    ①IE中XDomainRequest对象

    1)XDR与XHR区别

    □cookie不会随请求发送,也不会随响应返回。

    □只能设置请求头部信息中的Content-Type字段。

    □不能访问响应头部信息。

    □只支持GET和POST请求。

    □XDR只能访问Access-Control-Allow-Origin头部设置为有当前域的资源。

    2)所有XDR请求都是异步执行的,不能创建同步请求。

    □返回请求之后,会触发load事件,响应的数据也会保存在response属性中。

    □接收到响应后,只能访问响应的原始文本,没有办法确定响应的状态代码。

    □响应有效会触发load事件,如果失败(包括响应中缺少Access-Control-Origin头部)就会触发error事件。

    □XDR也支持timeout属性以及ontimeout事件处理程序。

    □为了支持POST请求,XDR对象提供了ontentType属性,用来表示发送数据的格式。

    □在请求返回前调用abort()方法可终止请求。

    var xdr = new XDomainRequest();

    xdr.onload = function(){

    alert(xdr.responseText);

    };

    xdr.timeout = 1000;

    xdr.ontimeout = function(){

    alert("Request took too long.");

    };

    xdr.open("get","http://www.xx.com/page/");

    xdr.send(null);

    ②Firefox

    1)要求远程资源有权决定自身是否可以被远程浏览器访问。

    □这需要通过设置Access-Contro-Allow-Origin头部实现。

    □要访问另一个域资源,可以使用标准XHR对象,并为open()方法传入一个绝对URL。

    2)与IE中XDR对象不同,跨域XHR对象允许访问status和statusText属性,也支持同步请求。

    3)跨域XHR的额外限制如下:

    □不能使用setRequestHeader()设置自定义头部。

    □不会发送也不会接受cookie

    □getAllRequestponseHeaders()方法只能返回空字符串。

    3.JSON

    ①JSON是纯文本,而不是JavaScript代码。JSON的设计意图在服务器端构建格式化的数据,然后再将数据发送给浏览器。

    ②由于JSON在JavaScript中相当于对象和数组,因此JSON字符串可以传递给eval()函数,让其解析并返回一个对象或数组的实例。

    ③如果你是自己编写代码来对JSON求值,最好将输入文本放在一对圆括号中。因为eval()在对输入的文本求值时,是将其作为JS代码而非数据格式看待。在对以左花括号开头的对象求值时,就好像是遇到一个没有名字的JavaScript语句,会导致错误。将文本放在一对圆括号中可以解决这个问题,因圆括号表示值而不是语句。

    var object1 = eval("{}");  //抛出错误

    var object2 = eval("({})");  //没有问题

    var object3 = eval("(" + jsonText + ")");  //通用解决方案

    3.1在Ajax中使用JSON

    ①Douglas Crockford的JSON序列化器/解析器。www.json.org/js.html

    ②在上述库中,有一个全局JSON对象,有两个方法:parse()和stringify()。

    ③parse()方法:

    □两个参数:JSON文本和一个可选的过滤函数。在传入的文本是有效地JSON情况下,parse()方法返回传入数据的一个对象表示。

    □例子:var object = JSON.parse("{}"); 与直接使用eval()不同的是,这里不需要传入的文本家圆括号(内部自动处理)。

    □第二个参数是一个函数,这个函数以一个JSON键和值作为参数。要想让作为参数的键出现在结果对象中,该函数必须返回一个值。

    var jsonText = "{\"name\":\"Nicholas\",\"age\":29,\"author\":true}";

    var object = JSON.parse(jsonText,function(key,value){

    switch(key){

    case "age" : return value+1;

    case "author" : return undefined;

    default : return value;

    }

    });

    alert(object.age);  //30

    alert(object.author); //undefined

    ④JSON同样也是向服务器发数据的流行格式。发送数据时,一般会把JSON放到POST请求主体中,而JSON对象的stringify()方法正是为此而设计。

    ⑤stringify()方法:

    □三个参数:要序列化的对象、可选的替换函数(用于替换未受支持的JSON值)和可选的缩进说明符(可以是每个级别缩进的空格数,也可以是用来缩进的字符)。

    var contact = {

    name : "Nicholas C. Zakas",

    email : "nicholas@some-domain-name.com"

    };

    var jsonText = JSON.stringify(contact);

    alert(jsonText);

    □JSON序列化支持的类型:字符串、数值、布尔值、null、对象、数组和Date(Date将被换成字符串形式)。其他不支持类型将被移除,可通过stringify()第二个参数所传入的函数改变行为。

    3.2安全

    ①JSON缺点:使用eval(),有可能受到XSS攻击。

    ②建议使用Crockford的库,可妥当解析JSON字符串,过滤其中恶意代码。降低遭受代码式XSS攻击的可能性。

  • 相关阅读:
    利用sqlmap进行mysql提权的小方法(win与liunx通用)
    冰蝎绕过阿里云盾和天眼监控的新方法
    关于渗透的小技巧整理
    入侵者已经拿到了主机的管理员权限,请你列举几种留后门的方法:(windows和LINUX系统均可)
    Mysql root账号general_log_file方法获取webshell
    tomcat put上传漏洞批量利用程序v1.1
    ios10.3.3快速越狱指南
    Android的虫洞漏洞挖掘方法研究
    【原创】TransHost远控程序分析
    【转载】微信数据库解密算法
  • 原文地址:https://www.cnblogs.com/chemandy/p/2161984.html
Copyright © 2011-2022 走看看