开发者

$.ajax to dojo.xhr for use in sharepoint web-services not working

开发者 https://www.devze.com 2023-04-04 09:39 出处:网络
This function uses jquery and Dojo libraries to fetch infor from Sharepoint. I want to use only Dojo. How can I port the jquery part to Dojo?

This function uses jquery and Dojo libraries to fetch infor from Sharepoint. I want to use only Dojo. How can I port the jquery part to Dojo?

To be specific, the $.ajax call needs to be converted to dojo.xhrPost

$.ajax({
  url: url,
  type: "POST",
  async: false,
  dataType: "xml",
  data: getSOAPEnvelope(fields, guid),
  complete: function (xData, status) {//parse xml to json},
  contentType: "text/xml"
})

This is my attempt:

dojo.xhrPost({
  url: url,
  sync:true,                            //in jquery, sync     => async
  handleAs:"xml",                       //in jquery, handleAs => dataType
  content:getSOAPEnvelope(fields, guid),//in jquery, content  => data
  load: (fn from 1.1 section goes here) //in jquery, load     => complete
  headers: {Content-Type:"text/xml"}    //in jquery is contentType:"text/xml"
  }
});

And this is the full original (unported) function:

    /*
    Returns a json object from a sharepoint list 
    url and guid arguments are strings (without the {})
    fields is an optional array of fileds to be output. this will reduce teh size of the response.
    uniqueFields is an optional array of fileds to be filtered. For example: 
    if the list has
    row,fruit,color,size
    1,banana,green,small
    2,banana,yellow,small
    3,apple,yellow,medium
    4,apple,green,small
    5,apple,red,small
    for a list of fruits, you put: getJsonItems(url,guid,true,['row',fruit','color'],['fruit']) -> returns rows 1 and 3 
    for a list of fruit sizes, do: getJsonItems(url,guid,true,false,['fruit','size']) -> returns all columsn for items (1,3,4)
    */
    dojo.require("dojox.xml.parser");
    function getJsonItems(url, guid, fields, uniqueFields) {

        //prepare the SOAP envelope

        var jsonItems = []
        var pkHash = []
        //1. fetch xml data from server and parses into json
        $.ajax({
            url: url,
            type: "POST",
            async: false,
            dataType: "xml",
            data: getSOAPEnvelope(fields, guid),
            complete:
            //1.1 when data is received from the server, parse it to json
                function (xData, status) {

                    //1.1.1 convert xml to DOM for easier manipulation
                    var dom = dojox.xml.parser.parse(xData.responseXML.xml)

                    //1.1.2 get xml rows
                    var rows = dom.getElementsByTagName("z:row")

                    //1.1.3 parse each xml row and add it to jsonItems array
                    dojo.forEach(rows, function (row, i) {
                        var jsonItem = {};
                        var uniqueKey = "";
                        //1.1.3.1 parse each xml row into json object. (It removes the ";#" prefix and other MS junk for lookup values or values with spaces)
                        for (var j = 0; j < row.attributes.length; j++) {

                            //1.1.3.1.1 parse the col name by removing ows_, replacing hex numbers (x_00xx_) and trimming spaces
                            var col = row.attributes[j].nodeName.replace("ows_", "").replace(/_x([A-F\d]{4})_/gi, function (str, hexNum) { return eval("\"\\u" + hexNum + "\"") }).replace(/^\s+|\s+$/g, "$1")

                            var val = row.attributes[j].nodeTypedValue.replace(/\d+;#/, "")

                            //1.1.3.2 add property to jsonItem
                            if (dojo.indexOf(fields?fields:[col], col) >开发者_开发百科= 0) jsonItem[col] = val;

                            //1.1.3.3 filter duplicates based on uniqueFields
                            if (dojo.indexOf(uniqueFields?uniqueFields:[col], col) >= 0) uniqueKey += col + val;
                        }

                        //1.1.3.3 add to uniqueKey to pkHash
                        if (dojo.indexOf(pkHash, uniqueKey) < 0) {
                            pkHash.push(uniqueKey);
                            jsonItems.push(jsonItem)
                        }

                    })
                },
            contentType: "text/xml"
        })

        //2. return parsed xml to json ojbect
        return jsonItems
    }


    function getSOAPEnvelope(fields,guid){

        //prepare ViewFields element
        var viewFields = "";
        if (fields) {
            viewFields = "<viewFields><ViewFields Properties='True'>"
            dojo.forEach(fields, function (e) {viewFields += "<FieldRef Name='"+e+"'/>"});
            viewFields += "</ViewFields></viewFields>";
        }

        var envelope = "<soapenv:Envelope xmlns:soapenv='http://schemas.xmlsoap.org/soap/envelope/'> \
                        <soapenv:Body> \
                            <GetListItems xmlns='http://schemas.microsoft.com/sharepoint/soap/'> \
                                <listName>{" + guid + "}</listName>\
                                " + viewFields + " \
                            </GetListItems> \
                        </soapenv:Body> \
                     </soapenv:Envelope>";

        return envelope;
    }


If you use content in dojo.xhr, Dojo will treat the content as a JSON object and convert it using form encoding. For example, if you pass {a : 1, b : 2} as content, the actual data sent to server is a=1&b=2.

Your getSOAPEnvelope function actually returns a simple string, so you can not use content. Just remove content and use postData instead. For example,

dojo.xhrPost({
  url: url,
  sync:true,                            //in jquery, sync     => async
  handleAs:"xml",                       //in jquery, handleAs => dataType
  postData:getSOAPEnvelope(fields, guid),//in jquery, content  => data
  load: (fn from 1.1 section goes here) //in jquery, load     => complete
  headers: {Content-Type:"text/xml"}    //in jquery is contentType:"text/xml"
}
});


I wish I can use Firebug but I have to use fiddler because FF will not SSO on Sharepoint. I am using VS 2010 to debug and it breakes when the "access denied error" IE dialog shows at xhr.open function. This prevents anything to be posted even if I ignore or continue the error. This happens at line 11208 of dojo.xd.js.uncompressed ver 1.6 from google cdn:

    // IE 6 is a steaming pile. It won't let you call apply() on the native function (xhr.open).
    // workaround for IE6's apply() "issues"
    xhr.open(method, ioArgs.url, args.sync !== true, args.user || undefined, args.password || undefined);
    if(args.headers){
        for(var hdr in args.headers){
            if(hdr.toLowerCase() === "content-type" && !args.contentType){
                args.contentType = args.headers[hdr];
            }else if(args.headers[hdr]){
                //Only add header if it has a value. This allows for instnace, skipping
                //insertion of X-Requested-With by specifying empty value.
                xhr.setRequestHeader(hdr, args.headers[hdr]);
            }
        }
    }

the arguments values being passed are:

    method:POST, 
    ioArgs.url:*my sharepoint url*, 
    args.user:*undefined*, 
    args.password:*undefined*

I have a feeling it's the username / pwd. Just something missing on the dojo.XHRPost params or simply I need to use other dojo function (such as dojo.io.iframe)

Now, if you want to compare the XHR responses, with jquery I get:

  1. A confirmation box from IE stating that "the page is accessing information that is not under its control with a security risk"
  2. A first attempt to request info from _vti_bin/lists.asmx with a 401 Unauthorized response
  3. A second succesful attempt to request the same

Here are the details:

1st Request with jquery:

POST https://a101.sharing.***.com/sites/HOU000169/_vti_bin/lists.asmx HTTP/1.1
Accept: application/xml, text/xml, */*
Accept-Language: en-us
x-requested-with: XMLHttpRequest
Content-Type: text/xml; charset=utf-8
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; WOW64; Trident/4.0; SLCC1; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30618; .NET4.0C; .NET4.0E; MS-RTC LM 8)
Host: a101.sharing.***.com
Content-Length: 0
Connection: Keep-Alive
Cache-Control: no-cache
Cookie: WSS_KeepSessionAuthenticated=80
Authorization: NTLM TlRMTVNTUAABAAAAB4IIogAAAAAAAAAAAAAAAAAAAAAGAHEXAAAADw==

1st Response

HTTP/1.1 401 Unauthorized
Content-Length: 1539
Content-Type: text/html
Server: Microsoft-IIS/6.0
WWW-Authenticate: NTLM TlRMTVNTUAACAAAAEAAQADgAAAAFgomioKDRqMorlxAAAAAAAAAAALQAtABIAAAABQLODgAAAA9BAE0ARQBSAEkAQwBBAFMAAgAQAEEATQBFAFIASQBDAEEAUwABABgASABPAFUASQBDAC0AUwAtADYAMAA3ADgABAAkAGEAbQBlAHIAaQBjAGEAcwAuAHMAaABlAGwAbAAuAGMAbwBtAAMAPgBoAG8AdQBpAGMALQBzAC0ANgAwADcAOAAuAGEAbQBlAHIAaQBjAGEAcwAuAHMAaABlAGwAbAAuAGMAbwBtAAUAEgBzAGgAZQBsAGwALgBjAG8AbQAAAAAA
MicrosoftSharePointTeamServices: 12.0.0.6219
X-Powered-By: ASP.NET
Date: Fri, 16 Sep 2011 16:49:31 GMT
Proxy-Support: Session-Based-Authentication

2nd try

POST https://a101.sharing.***.com/sites/HOU000169/_vti_bin/lists.asmx HTTP/1.1
Accept: application/xml, text/xml, */*
Accept-Language: en-us
x-requested-with: XMLHttpRequest
Content-Type: text/xml; charset=utf-8
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; WOW64; Trident/4.0; SLCC1; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30618; .NET4.0C; .NET4.0E; MS-RTC LM 8)
Host: a101.sharing.***.com
Content-Length: 433
Connection: Keep-Alive
Cache-Control: no-cache
Cookie: WSS_KeepSessionAuthenticated=80
Authorization: NTLM TlRMTVNTUAADAAAAGAAYAKYAAABmAWYBvgAAABAAEABYAAAAJAAkAGgAAAAaABoAjAAAAAAAAAAkAgAABYKIogYAcRcAAAAPpsehFcQrqLsci4ksbHmc0kEATQBFAFIASQBDAEEAUwBKAG8AcwBlAC4ATAAuAEwAZQB2AGkAYQBnAHUAaQByAHIAZQBIAE8AVQBCAFQAQwAtAEQALQA2ADkANgAxAAFMM6NEtmJORCTtsBAnHHWRUNRPM01quP7zKT4VD35T2Y4glT4PV6YBAQAAAAAAAFFUfpuQdMwBkVDUTzNNargAAAAAAgAQAEEATQBFAFIASQBDAEEAUwABABgASABPAFUASQBDAC0AUwAtADYAMAA3ADgABAAkAGEAbQBlAHIAaQBjAGEAcwAuAHMAaABlAGwAbAAuAGMAbwBtAAMAPgBoAG8AdQBpAGMALQBzAC0ANgAwADcAOAAuAGEAbQBlAHIAaQBjAGEAcwAuAHMAaABlAGwAbAAuAGMAbwBtAAUAEgBzAGgAZQBsAGwALgBjAG8AbQAIADAAMAAAAAAAAAABAAAAACAAAMzqw8jpvzbRjHmde0Fhp8Dw6btoC9d5sGE8/LukEd0PCgAQAOq5JkugZHw/GB0+NrLsKCMJADYASABUAFQAUAAvAGEAMQAwADEALgBzAGgAYQByAGkAbgBnAC4AcwBoAGUAbABsAC4AYwBvAG0AAAAAAAAAAAA=

<soapenv...the hole soap envelope

2nd Response

HTTP/1.1 200 OK
Cache-Control: private, max-age=0
Content-Length: 103794
Content-Type: text/xml; charset=utf-8
Server: Microsoft-IIS/6.0
MicrosoftSharePointTeamServices: 12.0.0.6219
X-Powered-By: ASP.NET
X-AspNet-Version: 2.0.50727
Set-Cookie: WSS_KeepSessionAuthenticated=80; path=/
Set-Cookie: MSOWebPartPage_AnonymousAccessCookie=80; expires=Fri, 16-Sep-2011 17:19:31 GMT; path=/
Date: Fri, 16 Sep 2011 16:49:31 GMT

<?xml version...and the rest of my xml response that I'll later on parse to json

Remember that jquery works fine from the desktop after accepting the security risk but it does not work with dojo. If I move the file to the server itself, it works fine.

Bottom line question

At the end, my main concern is, why jquery can bypass the cross-domain security but not with dojo? Maybe with dojo.io.iframe but so far, no luck!


I think I found the problem. I simplified to the minimum and dojo.xhr works fine. There are some slight differences:

$.ajax({
    url: url,
    type: "POST",
    async: false,
    dataType: "xml",
    data: soap,
    complete: function (xData, status) {
        alert(xData.responseXML.xml)
    },
    contentType: "text/xml; charset=utf-8"
})


dojo.xhrPost({
    url: url,
    sync: true,
    handleAs: "xml",
    postData: soap,
    load: function (xData, status) {
        alert(xData.xml )
    },
    headers: { "Content-Type": "text/xml; charset=utf-8;" }
})

Here is the complete code. You can copy paste this script and run it from your desktop because everything is cdn and the sharepoint library I use for testing is public

    <html>
     <head>
      <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.js"></script>
      <script src="https://ajax.googleapis.com/ajax/libs/dojo/1.6/dojo/dojo.xd.js.uncompressed.js" djConfig="parseOnLoad: true"></script>


         <script>

              var url = "http://msftplayground.com/_vti_bin/lists.asmx";  //this is a public sharepoint site, so you don't have to change anything
              var soap = '<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><GetListCollection xmlns="http://schemas.microsoft.com/sharepoint/soap/" /></soap:Body></soap:Envelope>';

              function jqueryAjax() {
                    dojo.byId("xmlResp").value = "response from $.ajax: ";
                    $.ajax({
                              url: url,
                              type: "POST",
                              async: false,
                              dataType: "xml",
                              data: soap,
                              complete: function (xData, status) { dojo.byId('xmlResp').value += xData.responseXML.xml },
                              contentType: "text/xml; charset=utf-8"
                    })
              }

              function dojoXhr() {
                    dojo.byId("xmlResp").value = "response from dojo.xhrPost: ";
                    dojo.xhrPost({
                         url: url,
                         sync: true,
                         handleAs: "xml",
                         postData: soap,
                         load: function (xData, status) {
                              dojo.byId('xmlResp').value += xData.xml 
                         },
                         headers: { "Content-Type": "text/xml; charset=utf-8;" }
                    })
         }

         </script>

    </head>
    <body>
    <pre>
    <button onclick="jqueryAjax()">test jquery</button>
    <button onclick="dojoXhr()">test dojo</button>
    Response:
    <textarea id="xmlResp" style="height:500px;width:99%;overflow:auto"></textarea>
    </pre>
    </body>
    </html>
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号