Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 15 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
15
Dung lượng
363,85 KB
Nội dung
while the user is still manipulating the information within the browser. This represents the heart of Ajax and is the core advantage that it represents within traditional browser applications. A user can continue to work within the browser application uninterrupted, while in the background a request is sent and a response that contains the result of some server-side processing is received. Synchronous Requests Take a look at a following simple code example of a synchronous operation and then take a look at the explanation of exactly what is occurring that follows. Note: The code for the inclusion of the script include file mentioned previously has been omitted for brevity. Try It Out A Synchronous Operation function MakeXMLHTTPCall() { var xmlHttpObj; xmlHttpObj = CreateXmlHttpRequestObject(); if (xmlHttpObj) { xmlHttpObj.open(“GET”,”http://” + location.host + “/XmlHttpExample1/DataFile.xml”, false); xmlHttpObj.send(null); alert(“Request/Response Complete.”); } } How It Works The preceding code sample is very simple, however it does show the basic usage of the XMLHTTP object. If you examine the code in detail, you’ll see the following: 1. First you create a new XMLHTTP object and assign it to a variable. 2. After checking if the object is not null, that is, that the object creation in Step 1 was successful, you execute the open method passing in three parameters: xmlHttpObj.open(“GET”,”http://” + location.host + “/XmlHttpExample1/DataFile.xml”, false); ❑ The first parameter, “GET”, is the type of request to make (this can be any of the stan- dard HTTP verbs “ GET”, “POST”, “PUT”, or “HEAD”) ❑ The second parameter is the server address, or endpoint, to make the request to. In this case, it’s an XML file located at http://localhost/XmlHttpExample1DataFile.xml. ❑ The third parameter, false, indicates whether a synchronous or asynchronous request should take place. In this case, false indicates that a synchronous request should occur. 3. The send method is executed on the XMLHTTP object instance to perform the actual request. xmlHttpObj.send(null); 81 The XMLHttpRequest Object 07_78544X ch04.qxp 7/18/06 3:12 PM Page 81 4. Since you specified that a synchronous operation should occur, the next alert statement to dis- play a message box is not shown until the request has completed executing and returns from the server. alert(“Request/Response Complete.”); As already mentioned, the previous example shows a synchronous operation that offers no real change from the standard request/response paradigm that is prevalent in web applications. A request is issued, the user waits until a response is received, and the user can continue. Now, we can change this to be asynchronous. Asynchronous Requests Examine the code that follows, which performs exactly the same operation as the previous example, but operates in an asynchronous manner. Note: The code for the inclusion of the script include file men- tioned previously has been omitted for brevity. Try It Out An Asynchronous Operation function MakeXMLHTTPCall() { var xmlHttpObj; xmlHttpObj = CreateXmlHttpRequestObject(); if (xmlHttpObj) { xmlHttpObj.open(“GET”,”http:// “ + location.host + “/XmlHttpExample1/DataFile.xml”, true); xmlHttpObj.onreadystatechange = function() { if ( xmlHttpObj.readyState == READYSTATE_COMPLETE ) { alert(“Request/Response Complete”); } } xmlHttpObj.send(null); } } How It Works There are two main differences in this example as compared to the initial synchronous example: xmlHttpObj.open(“GET”,”http://” + location.host + “/XmlHttpExample1/DataFile.xml”, true ); The first difference is the use of the true parameter as the last argument to the open method to indicate that the request should be executed in an asynchronous manner. 82 Chapter 4 07_78544X ch04.qxp 7/18/06 3:12 PM Page 82 The second difference is the use of the onreadystatechange event and the readyState property value. The code: xmlHttpObj.onreadystatechange = function() assigns a function or event handler to the onreadystatechange event. When the state of the object changes, this event is triggered and the function is executed. The code: if ( xmlHttpObj.readyState == READYSTATE_COMPLETE ) checks the state of the object to determine if any action should be taken. The ready state of the XMLHttpRequest object actually contains a numeric value representing its state. The numeric value being checked for in the preceding example is a value of 4, which is represented by the variable READYSTATE_COMPLETE. The valid list of XMLHttpRequest ready states is listed in the following table: Value Description 0 Uninitialized 1 Loading 2 Loaded 3 Interactive 4 Complete A convenient place to put the values of the XMLHttpRequest ready states is in the library that was defined earlier to house the function that created an XMLHttpRequest object. This makes it possible to add meaning to what appears to be an arbitrary value. The following code: /* Common values for the ReadyState of the XMLHttpRequest object */ var READYSTATE_UNINITIALIZED = 0; var READYSTATE_LOADING = 1; var READYSTATE_LOADED = 2; var READYSTATE_INTERACTIVE = 3; var READYSTATE_COMPLETE = 4; has been added to the JavaScript common library defined earlier in the chapter. This means that the pre- vious example, showing an asynchronous call, equates to the following line: if ( xmlHttpObj.readyState == 4 ) However, the line currently is written as: if ( xmlHttpObj.readyState == READYSTATE_COMPLETE ) which makes it much more readable and adds clarity as to what is being tested in the code fragment. So, the JavaScript code in the example simply checks the ready state of the object to determine if the asynchronous request has completed. If the ready state is complete, then you continue processing your response data (if any). 83 The XMLHttpRequest Object 07_78544X ch04.qxp 7/18/06 3:12 PM Page 83 So far, you have seen to how to perform an asynchronous request to the server and wait for the response by assigning an event handler. This forms the basis of all asynchronous request functionality, and you will use this as the foundation for more complex examples as you progress. Dealing with Response Data In most scenarios, you will want to retrieve and process some response data from the server as part of your asynchronous call. In the previous examples, you have requested an XML data file but have not attempted to process the data returned. You have simply indicated the request has completed. To retrieve data from the response stream once the request is completed, you can use the following properties: ❑ responseText — This property returns the response data as a string. ❑ responseXML — This property returns the response data as an XML document object. This object can be examined and parsed using the standard methods and properties available from the W3C Document Object Model (DOM) node tree in a read-only (cannot be updated) fashion. 84 Chapter 4 A Note on Security It is worth noting at this point that there are security restrictions that are placed on the use of the XMLHttpRequest object. All browsers that implement the XMLHttpRequest object implement a security policy called the “same origin” policy. This means that a request issued using an XMLHttpRequest object must be to a server of the same origin from which it was loaded. For example, if a web page were loaded from www.yourserver.com/somepage .aspx , then all requests issued using the XMLHttpRequest must be serviced by the same host, that is, www.yourserver.com. Any deviation to the server/host name, pro- tocol, or the port will break the security policy. For example, given the previous exam- ple server, if a subsequent XMLHttpRequest were issued to www.anotherserver .com/anotherpage.aspx , then this would fail the security policy. Similarly, trying to access www.yourserver.com/somepage.aspx will also fail because the protocol is specified as https: whereas previously the code originated from an http: address. This policy makes sense because it means that web pages cannot simply issue requests to any server they choose and potentially become yet another client capable of initiat- ing denial-of-service attacks to servers (that is, flooding the servers with requests in order to bring down or disable the service/server). Unfortunately, different browsers implement the “same origin” security policy differ- ently. Most will fail in some way if a request is issued to a server that is not deemed the origin, and it is very hard to accommodate all browsers when performing these types of requests and handling the errors. The recommended practice is simply to not use requests that break the same origin policy. Issue a request back to the originating server as already discussed and let the server make any cross-domain/nonoriginating server calls on your behalf using standard server-based programming techniques. 07_78544X ch04.qxp 7/18/06 3:12 PM Page 84 Using the responseText Property The responseText property is the simplest of the methods to utilize data from the response. All data that is part of the response is returned as a single string. This property is useful for simple operations where only a singular piece of data is returned and manipulated or displayed by the page. Alternatively, the data returned may be in a proprietary format that requires specialized parsing by the client. To have a look at how you use this property in code, you can enhance the existing sample to display data returned from the asynchronous call on the web page. Try It Out Returning Response Data As a String This web page will be a very simple page with a button and a section to display the response data. The HTML fragment that follows shows the “body” section of the HTML page. <body> <form id=”Form1” method=”post” runat=”server”> <input type=”button” onclick=”MakeXMLHTTPCall();” value=”Test XMLHTTP Call” /> <br /> <br /> <div id=”divResults”>{no results}</div> </form> </body> The example JavaScript code will now look like the fragment that follows. The emphasized text shows what has been added compared to the previous examples: <script type=”text/javascript” src=”CommonAJAXLibrary.js”></script> <script type=”text/javascript”> function MakeXMLHTTPCall(){ var xmlHttpObj = CreateXmlHttpRequestObject(); if (xmlHttpObj) { xmlHttpObj.open(“GET”,”http://” + location.host + “/XmlHttpExample1/DataFile.xml”, true); xmlHttpObj.onreadystatechange = function() { if ( xmlHttpObj.readyState == READYSTATE_COMPLETE ) { // Extract the response text here and place in the div element. document.getElementById(“divResults”).childNodes[0].nodeValue = xmlHttpObj.responseText; } } xmlHttpObj.send(null); } } </script> 85 The XMLHttpRequest Object 07_78544X ch04.qxp 7/18/06 3:12 PM Page 85 The code sets the value of the text property of the page’s single div element to the responseText of the returned data. For this simple example, the DataFile.xml file that is requested using the XMLHttpRequest object contains the following: <?xml version=”1.0” encoding=”utf-8” ?> <Customers> <Customer> <Firstname>Joe</Firstname> <Lastname>Bloggs</Lastname> <email>joe@bloggs.com</email> </Customer> <Customer> <Firstname>Alan</Firstname> <Lastname>Anonymous</Lastname> <email>anon@ymous.com</email> </Customer> <Customer> <Firstname>Marvin</Firstname> <Lastname>Martian</Lastname> <email>marvin@mars.com</email> </Customer> </Customers> When the page executes, and the button is clicked, the web browser displays the result shown in Figure 4-1. Figure 4-1 86 Chapter 4 07_78544X ch04.qxp 7/18/06 3:12 PM Page 86 As you can see, the data contained within the XML file is rendered in the page in exactly the same way it is stored within the file. As mentioned previously, this might be okay for simple scenarios that require only a single unit of data or data that is in a proprietary format, but for more complex scenarios you’ll want to use the responseXML property. Using the responseXML Property In a majority of scenarios, you will want to return multiple result items. This might be a list of names to display in a drop-down list, a list of customers, or an object representation. The XML format is ideally suited to this, and direct support for this format is provided by the responseXML property of the XMLHttpRequest object. This property is a standard XML document object that can be examined and parsed using W3C DOM node tree methods and properties. For detailed reference material on the XML Document Object Model, visit http://msdn .microsoft.com/library/en-us/xmlsdk30/htm/xmmscxmlreference.asp . Try It Out Returning Response Data As an XML Document Object You can continue to modify the code example to extract values from the XML data that was retrieved and displayed in the previous example. Rather than reproduce the entire previous code sample, we will show only the modified section that replaces the added code from the previous example that used the responseText property. Examine the following code: if ( xmlHttpObj.readyState == READYSTATE_COMPLETE ) { var doc = xmlHttpObj.responseXML; var node = doc.selectSingleNode(“//Customers/Customer/Firstname/text()”); document.getElementById(“divResults”).childNodes[0].nodeValue = node.nodeValue; } Instead of simply displaying the entire set of returned data, you are extracting the text value of the first instance of the <Firstname> node. You do this by utilizing the selectSingleNode method, which takes an X Path expression as an argument and returns an XML node object if one is found or NULL if the X Path query is unsuccessful. With the returned node object, you assign the nodeValue property of the first element of the childNodes property, which itself is a property of the divResults element to the text value of the node. For those unfamiliar with the X Path language, you can think of it as a dynamic query language for XML documents that operates in a similar way to ANSI SQL for databases. Nodes, elements, and data can be queried and returned using X Path expressions. X Path expressions can contain conditional expressions and be quite complex. For a detailed reference on X Path expressions and the associated syntax, visit the W3C site at www.w3.org/TR/xpath, or for something a little more readable, try www.topxml.com/xsl/XPathRef.asp. This example is still fairly simplistic, though. Now, you’re going to take your newfound knowledge and apply this by creating a simple web page that allows you to make a selection from a list of customers and display the fullname and email address by doing a server-side lookup into your XML data file asynchronously. 87 The XMLHttpRequest Object 07_78544X ch04.qxp 7/18/06 3:12 PM Page 87 Enhancing Usability One of the primary reasons that the asynchronous capability of the XMLHttpRequest object has received so much attention lately is that it can remove the interruption of the user experience that would nor- mally occur when a postback, or server-side call, is required to gather some server-side data. In the example that follows, you will provide a list of names via a drop-down list gathered from the XML data file. When the user selects a name, a server call is issued to retrieve that data and extract the email address. Without using the asynchronous capability of the XMLHttpRequest object, this would require a postback, and the user would be forced to wait while the request was sent to the server and processed, and the results returned and displayed on the browser. Now that you have the ability to per- form a server request asynchronously, the call to retrieve data can be performed without interrupting the user interaction on the browser. It is, in effect, an invisible postback— a server request that is executed behind the scenes and in parallel to any user interface interaction. Try It Out Performing a Server Request Asynchronously Examine the code that follows, which is a fragment listing of a web page: <body onload=”LoadCustomers();”> <form id=”form1” runat=”server”> <div> <select id=”ddlCustomers” onchange=”DisplayCustomerDetails();”> <option value=””>- Select a Customer -</option> </select> <hr /> <div> <p>Details:</p> <span id=”spnDetailDisplay”>(You have not made a selection yet.)</span> </div> </div> </form> </body> </html> Within the ASP.NET form element <form id=”form1” runat=”server”> is a <select> element that acts as your customer drop-down list and a <span> element where you can display the customer details. You will also notice that the onload event of the document has a LoadCustomers() function assigned to it to initially load in the list of customers and that the onchange event of the <select> item has a DisplayCustomerDetails() function assigned to it to display the selected customers details once a selection is made. Firefox does not currently support the use of the selectSingleNode() and selectNodes() methods to access data within an XML document. To address this, the script include library includes some JavaScript code to enable this support. The code included was taken from the site http://km0ti0n.blunted.co.uk/mozXPath .xap . A full explanation of the details of this support is beyond the scope of this chapter; suffice it to say that it allows support of the selectSingleNode() and selectNodes() methods in the same way that Internet Explorer does. 88 Chapter 4 07_78544X ch04.qxp 7/18/06 3:12 PM Page 88 Next listed in the following code blocks are the JavaScript functions that accompany the page listing. The first function is a generic function to simply create an XMLHttpRequest object that you can use: <!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”> <html xmlns=”http://www.w3.org/1999/xhtml” > <head runat=”server”> <title>Untitled Page</title> <script type=”text/javascript”> // A “global” variable that is our XMLHttpRequest object reference. var xmlHttpObj = CreateXmlHttpRequestObject(); The next function is what is called when the document first loads and deals with loading the customer data from the server using the XMLHttpRequest object: // Function to load the customer selection data into the <SELECT> drop list control function LoadCustomers() { if (xmlHttpObj) { // We want this request synchronous xmlHttpObj.open(“GET”,”http:// “ + location.host + “/XmlHttp_Chap4/DataFile.xml”, false); // Execute the request xmlHttpObj.send(null); // If the request was ok (ie. equal to a Http Status code of 200) if (xmlHttpObj.status == 200) { var xmlDoc = xmlHttpObj.responseXML; // Our list of <CUSTOMER> nodes selected using the X Path argument //var nodes = xmlDoc.selectNodes(“//Customers/Customer”); var nodes = xmlDoc.selectNodes(“//Customers/Customer/Lastname/text()”); // Obtain a reference to the <SELECT> drop list control. var ctrl = document.getElementById(“ddlCustomers”); for (var i=0; i < nodes.length; i++) { // Get the lastname element from our XML data document var lastName = nodes[i].nodeValue; // Create a new <OPTION> node. var htmlCode = document.createElement(‘option’); // Add the new <OPTION> node to our <SELECT> drop list ctrl.options.add(htmlCode); // Set the <OPTION> display text and value; htmlCode.text = lastName; htmlCode.value = lastName; } } else 89 The XMLHttpRequest Object 07_78544X ch04.qxp 7/18/06 3:12 PM Page 89 { alert(‘There was a problem accessing the Customer data on the server.!’); } } } In the preceding code, you will notice the use of a literal number 200 in the following line of code: if (xmlHttpObj.status == 200) This is another perfect candidate to place into the common script include file. The code can be defined in the following manner: /* Common values for HTTP status codes */ var HTTPSTATUS_OK = 200; which means that any code comparing the HTTP status codes as in the previous example can be replaced with the following line of code: if (xmlHttpObj.status == HTTPSTATUS_OK) This makes the code much easier to read and maintain. Finally, you have the JavaScript function that deals with displaying a customer’s details once a selection is made from the drop-down list: function DisplayCustomerDetails() { if (xmlHttpObj) { // We want this request asynchronous xmlHttpObj.open(“GET”,”http:// “ + location.host + “/XmlHttp_Chap4/DataFile.xml”, true); xmlHttpObj.onreadystatechange = function() { if ( xmlHttpObj.readyState == READYSTATE_COMPLETE ) { var ctrl = document.getElementById(“ddlCustomers”); var doc = xmlHttpObj.responseXML; var lastName = ctrl.options[ctrl.selectedIndex].value; var node = doc.selectSingleNode(“//Customers/Customer[Lastname=’” + lastName + “‘]”); var details = ‘Fullname: ‘ + node.selectSingleNode(‘Firstname/text()’).nodeValue + ‘ ‘ + lastName + ‘. Email: ‘ + node.selectSingleNode(‘email/text()’).nodeValue; document.getElementById(“spnDetailDisplay”).childNodes[0].nodeValue = details; } 90 Chapter 4 07_78544X ch04.qxp 7/18/06 3:12 PM Page 90 [...]... ability to respond to requests with more direct control over the response data Essentially, an HTTP handler exists very early in the ASP.NET processing pipeline and can deal directly with requests without having to worry about HTML data being generated by the page and the unnecessary burden of the entire page lifecycle Additionally, the handler need not be concerned with having the initial request... An example follows where the parameter arg is being passed with a value of 123 xmlHttpObj.open(“GET”,”http://” + location.host + “/XmlHttpExample1/WebForm1.aspx?arg=123”, true); This method of passing arguments to the server is typically used with a “GET” request (or the “GET” verb) as shown in the preceding code; however, it can also be used with “POST” requests as well as shown in the following example:... you typically want to respond with some customized data, quite often in the form of a custom XML document While the preceding example does achieve that, you also don’t want to have to worry about what ASP.NET may add to the response as part of its page-processing pipeline Not only does this add unnecessary processing overheard but in some instances may also cause issues with the response data and the... drop-down list Within the DisplayCustomerDetails(), you define a function that is executed when the appropriate readystate of the request has been reached (readystate == READYSTATE_COMPLETE) You then use an X Path expression to locate the node matching your selected customer, extract the details of the customer from the XML data file using the selectSingleNode method, and display those details within the... Out Using a HTTP Handler To demonstrate the use of a HTTP handler to accept arguments sent from an XMLHttpRequest object, you first define the user interface within the web page, as shown in the following code This simply shows a drop-down list with a list of three customers When one of the customers is selected, that customer ID is used as part of the asynchronous request to request a specific set... the entire page lifecycle Additionally, the handler need not be concerned with having the initial request be a properly formed page but can instead have it be a custom formatted message that has meaning within the context of your application Often, this is an XML document used to transfer data between the client and the server HTTP handlers are a way to hook into the early stages of the ASP.NET processing... may be either a relative or complete URL The async parameter specifies whether the request should be handled asynchronously or not true means that script processing carries on after the send() method, without waiting for a response false means that the script waits for a response before continuing script processing send(content) Sends the request setRequestHeader(“label”,”value”) 92 Description Adds . information within the browser. This represents the heart of Ajax and is the core advantage that it represents within traditional browser applications. A user can continue to work within the browser. to requests with more direct control over the response data. Essentially, an HTTP handler exists very early in the ASP. NET processing pipeline and can deal directly with requests without having. passed with a value of 123. xmlHttpObj.open(“GET”,”http://” + location.host + “/XmlHttpExample1/WebForm1.aspx?arg=123”, true); This method of passing arguments to the server is typically used with