Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 56 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
56
Dung lượng
694,31 KB
Nội dung
379 int ch; while ((ch = iStrm.read()) != -1) bStrm.write(ch); // Place into image array byte imageData[] = bStrm.toByteArray(); // Create the image from the byte array im = Image.createImage(imageData, 0, imageData.length); } finally { // Clean up if (iStrm != null) iStrm.close(); } return (im == null ? null : im); } One drawback is the absence of a method to determine the length of the incoming data. However, this is not much of a concern, simply use a ByteArrayOutputStream to read the data and move the results into the destination array. Client Request Up to this point, we have not had a need to send or receive HTTP commands. The objective was simply to create a connection and download a stream of data. It's time to shift gears and learn how to create and manage communication through the HttpConnection class. HTTP is referred to as a request/response protocol: a client requests information, a server sends a response. The most common example is the interaction between a web browser (the client) and a web server. This section and the next will look at the details of the client request and the server response. Request Method A client request, known as the request entity, consists of three sections: request method, header and body. There are three request methods [4] available using HttpConnection (see Table 14.3). [4] Don't confuse the use of the word "method" in this context with a method in a Java class. Method as it is used here comes directly from the HTTP 1.1 specification, as in "a client sends a request to the server in the form of a request method." Table 14.3. Request Method: javax.microedition.io.HttpConnection Request Description GET Request information—data sent as part of URL POST Request information—data sent in separate stream HEAD Request only "metainformation" about a resource Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 380 All three request methods inform a server that a client is requesting some type of information. For GET and POST, what differs is how data from the client is transferred to the server. Both methods, along with HEAD, will be explained in a moment. You specify the request method of an HttpConnection through setRequestMethod() HttpConnection http = null; http = (HttpConnection) Connector.open(url); http.setRequestMethod(HttpConnection.GET); Table 14.4. Client Request Methods: javax.microedition.io.HttpConnection Method Description void setRequestMethod(String method) Set the request method (GET, POST or HEAD) void setRequestProperty(String key, String value) Set a request property (header information) String getRequestMethod() Get the current setting of the request method (GET, POST, HEAD) String getRequestProperty(String key) Get the current setting of a request property (header value) Using GET, the body (data) of the request becomes part of the URL. This is known as URL encoding. For example, using the analogy of a web browser, assume we have a form with two fields—color and font. The names of the fields on the form, as defined in the HTML code, are userColor and userFont. When the form has been completed and is ready to be sent, the values entered onto the form will be appended onto the URL. The resulting URL may look similar to the following: http://www.corej2me.com/formscript?userColor=blue&userFont=courier Notice the "?" after the URL. This signifies the end of the URL and start of the form data. All information is sent through "key-value" pairs such as userColor=blue, userFont=courier. [5] Multiple key-value pairs are separated with "&". [5] If there are spaces in the "value," replace them with "+". For example, "golf clubs" becomes "golf+clubs". Data submitted using POST is sent separately from the call to the URL. Put another way, the request to open a connection to a URL is sent as one stream, any data is sent as a separate stream. There are two major benefits of POST over GET: 1. POST has no limit to the amount of data that can be sent. This is not the case for the request method GET. When a server processes a GET request, the data from the end of the URL is stored in an environment variable (known as a query string). When sending a large amount of data, you run the risk of overrunning the environment variable. 2. POST sends data as a separate stream; therefore, the contents are not visible as part of the URL. [6] [6] POST in and of itself is not a secure means to send data. However, data sent as a separate stream is not as easily accessible to prying eyes as including the data as part of the URL. HEAD works in the same manner as GET, with the client sending the body as part of the URL. However, the server will not return a body in its response (more on the server response in a moment). Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 381 HEAD is generally used for retrieving information about a resource on a server. For example, you may want information about the last modified date of a file; however, it may not be necessary to retrieve the file contents. Header Information The second part of a client request is header information. The HTTP protocol defines over 40 header fields. Some of the more common are Accept, Cache-Control, Content-Type, Expires, If-Modified- Since and User-Agent. Headers are set by calling setRequestProperty(). HttpConnection http = null; http = (HttpConnection) Connector.open(url); http.setRequestMethod(HttpConnection.GET); http.setRequestProperty("If-Modified-Since", "Mon, 16 Jul 2001 22:54:26 GMT"); Body Data to be transferred from the client to the server is referred to as the body of the request. As mentioned, GET sends the body as part of the URL. POST sends the body in a separate stream. Server Response Once a client has packaged together the request method, header and body, and sent it over the network, it is now up to the server to interpret the request and generate a response known as the response entity. As with the client request, a server response consists of three sections: status line, header and body. Creating the response on the server side is beyond the scope of this discussion. Instead, we will concern ourselves with how to pull information from the server response. Status Line The status line indicates the outcome of the client request. For HttpConnection, there are over 35 status codes reported. HTTP divides the codes into three broad categories based on the numeric value mapped to the code. 1xx—information 2xx—success 3xx—redirection 4xx—client errors 5xx—server errors For example, HTTP_OK (status code 200) indicates the client request was successfully processed. When sending a response, a server includes the protocol version number along with the status code. Here are a few sample status lines: Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 382 HTTP/1.1 200 OK HTTP/1.1 400 Bad Request HTTP/1.1 500 Internal Server Error When interpreting status codes, you have two options: retrieve the message or the code. http.getResponseMessage(); http.getResponseCode(); The first returns only the text portion, such as OK or Bad Request. The later returns the code, such as 200 or 400. Table 14.5. Response Methods: javax.microedition.io.HttpConnection Method Description int getResponseCode() Get the response code (numeric) String getResponseMessage() Get the response message (text) Header Like the client, the server can send information through a header. These key-value pairs can be retrieved in various shapes and forms through the methods in Table 14.6 . Table 14.6. Server Response Methods: javax.microedition.io.HttpConnection Method Description String getHeaderField(int n) Get header field value looking up by index String getHeaderField(String name) Get header field value looking up by name long getHeaderFieldDate(String name, long def) Get named field as a long (representing the date) int getHeaderFieldInt(String name, int def) Get named field as an integer String getHeaderFieldKey(int n) Get header field key using index long getDate() Get header field "date" long getExpiration() Get header field "expires" long getLastModified() Get header field "last-modified" As an example, let's assume the server sent a header key-value pair content-type=text/plain. As a further assumption, the key-value pair will be the first entry in the header, and with this assumption, it will have an index value of 0. This header informs the client that the body of the response will be returned as plain text (as compared to HTML text, etc.). The following calls all reference the same key-value pair: // Header field at index 0: "content-type=text/plain" http.getHeaderField(0); // "text-plain" http.getHeaderField("content-type"); // "text-plain" http.getHeaderFieldKey(0); // "content-type" Custom Header Fields There are three methods for retrievin g s p ecific header fields sent from the server: Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 383 getDate(), getExpiration() and getLastModified(). However, with the remaining methods in Table 14-6 , you can retrieve any header a server may send, including custom headers, which are not defined in the HTTP specification. As an example, if a server created a custom header field Custom-ProductCode, the value of the header may be obtained as follows: String code = http.getHeaderField("Custom-ProductCode"); In Example 14.4 we'll create a custom header in a Java servlet and show how to search for the header inside a MIDlet. Body The body is the data sent from the server to the client. There are no methods defined in HttpConnection for reading the body. The most common means to obtain the body is through a stream, as shown in the following example. Example: Download a File To get a feel for setting up a client request and pulling apart a server response, let's create a MIDlet that requests to read the contents of a file over a network connection. The URL and connection request follow: url = "http://www.corej2me.com/midpbook_v1e1/ch14/getHeaderInfo.txt"; HttpConnection http = null; // Create the connection http = (HttpConnection) Connector.open(url); The client request is straightforward: // // Client Request // // 1) Send request method http.setRequestMethod(HttpConnection.GET); // 2) Send header information (this header is optional) http.setRequestProperty("User-Agent", "Profile/MIDP-1.0 Configuration/CLDC-1.0"); // 3) Send body/data - No data for this request Using a GET request method, send one header field and no data. The server response is a little longer, showing all the header fields (accessed in several ways) and the contents of the requested file. // // Server Response // Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 384 // 1) Get status Line System.out.println("Msg: " + http.getResponseMessage()); System.out.println("Code: " + http.getResponseCode()); // 2) Get header information if (http.getResponseCode() == HttpConnection.HTTP_OK) { System.out.println("field 0: " + http.getHeaderField(0)); System.out.println("key 0: " + http.getHeaderFieldKey(0)); System.out.println("content: " + http.getHeaderField("content-type")); // 3) Get data (show the file contents) String str; iStrm = http.openInputStream(); int length = (int) http.getLength(); if (length != -1) { // Read data in one chunk byte serverData[] = new byte[length]; iStrm.read(serverData); str = new String(serverData); } else // Length not available { ByteArrayOutputStream bStrm = new ByteArrayOutputStream(); // Read data one character at a time int ch; while ((ch = iStrm.read()) != -1) bStrm.write(ch); str = new String(bStrm.toByteArray()); bStrm.close(); } System.out.println("File Contents: " + str); } Step 3 (above) creates an InputStream and reads the body of the server response. The data sent from the server is the contents of the text file requested in the URL: http://www.corej2me.com/midpbook_v1e1/ch14/getHeaderInfo.txt" The output is shown in Figure 14–4. Figure 14-4. Server response from client GET request Example 14.2 ViewFile.java Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 385 /* * ViewFile.java * * Send client request (method, header, body) * Get server response (status, header, body) * */ import javax.microedition.midlet.*; import javax.microedition.io.*; import java.io.*; public class ViewFile extends MIDlet { private String url = "http://www.corej2me.com/midpbook_v1e1/ch14/getHeaderInfo.txt"; public void startApp() { try { processRequest(); } catch (Exception e) { System.err.println("Msg: " + e.toString()); } } private void processRequest() throws IOException { HttpConnection http = null; InputStream iStrm = null; try { // Create the connection http = (HttpConnection) Connector.open(url); // // Client Request // // 1) Send request method http.setRequestMethod(HttpConnection.GET); // 2) Send header information (this header is optional) http.setRequestProperty("User-Agent", "Profile/MIDP-1.0 Configuration/CLDC-1.0"); // http.setRequestProperty("If-Modified-Since", "Mon, 16 Jul 2001 22:54:26 GMT"); // If you experience IO problems, try // removing the comment from the following line //http.setRequestProperty("Connection", "close"); // 3) Send body/data - No data for this request // // Server Response // System.out.println("url: " + url); Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 386 System.out.println(" "); // 1) Get status Line System.out.println("Msg: " + http.getResponseMessage()); System.out.println("Code: " + http.getResponseCode()); // 2) Get header information if (http.getResponseCode() == HttpConnection.HTTP_OK) { System.out.println("field 0: " + http.getHeaderField(0)); System.out.println("field 1: " + http.getHeaderField(1)); System.out.println("field 2: " + http.getHeaderField(2)); System.out.println(" "); System.out.println("key 0: " + http.getHeaderFieldKey(0)); System.out.println("key 1 : " + http.getHeaderFieldKey(1)); System.out.println("key 2: " + http.getHeaderFieldKey(2)); System.out.println(" "); System.out.println("content: " + http.getHeaderField("content-type")); System.out.println("date: " + http.getHeaderField("date")); System.out.println("last-modified: " + http.getHeaderField("last-modified")); System.out.println(" "); // 3) Get data (show the file contents) String str; iStrm = http.openInputStream(); int length = (int) http.getLength(); if (length != -1) { // Read data in one chunk byte serverData[] = new byte[length]; iStrm.read(serverData); str = new String(serverData); } else // Length not available { ByteArrayOutputStream bStrm = new ByteArrayOutputStream(); // Read data one character at a time int ch; while ((ch = iStrm.read()) != -1) bStrm.write(ch); str = new String(bStrm.toByteArray()); bStrm.close(); } System.out.println("File Contents: " + str); // // Show connection information // System.out.println("Host: " + http.getHost()); System.out.println("Port: " + http.getPort()); Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 387 System.out.println("Type: " + http.getType()); } } finally { // Clean up if (iStrm != null) iStrm.close(); if (http != null) http.close(); } } public void pauseApp() { } public void destroyApp(boolean unconditional) { } } Example: if-modified-since Header Let's make one minor change to the previous example. Update the client section to look as follows: // // Client Request // // 1) Send request method http.setRequestMethod(HttpConnection.GET); // 2) Send header information (this header is optional) http.setRequestProperty("User-Agent", "Profile/MIDP-1.0 Configuration/CLDC-1.0"); http.setRequestProperty("If-Modified-Since", "Mon, 16 Jul 2001 22:54:26 GMT"); // 3) Send body/data - No data for this request When the server receives the header if-modified-since [7] it compares the date of the resource (on the server) with the date passed in the header. If the resource has not been modified since the requested date, no body is returned. You may find this helpful to keep the server from sending a body that has not changed since the last request. [7] Header requests are not case-sensitive. If-Modified-Since is equivalent to if-modified- since . Figure 14–5 shows the output of this MIDlet if the server does not return a body. Figure 14-5. Using "if-modified-since" header Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 388 Connection Header You'll notice several examples in this chapter include the following line: // If you experience IO problems, try // removing the comment from the following line // http.setRequestProperty("Connection", "close"); When setting this header to "close" it tells the server to close the connection after the response is sent. The reason for this explicit option has to do with the ability of a server to maintain a persistent connection with a client. When making multiple requests to a server, you may experience a performance increase because the connection is reused over multiple requests. However, if the Content-Length header is not used, or has an incorrect value, the client may block waiting for data that will never arrive. If you find you are having problems receiving data, remove the comment to force the server to close the connection once it has completed sending its response. If this fixes the problem, look closely at the Content- Length value that you are sending. Connection Information Once a connection has been established, there are several methods available to obtain information about the connection. Each is listed in Table 14.7 . Table 14.7. Connection Methods: javax.microedition.io.HttpConnection Method Description String getFile() Get filename from the URL String getHost() Get host from the URL int getPort() Get port from the URL String getProtocol() Get protocol from the URL String getQuery() Get the query string (only valid with a GET request) String getRef() Get the reference portion of URL [1] String getURL() Get the entire URL [1] This is optional. The reference portion is defined in RFC2396. Looking back at Example 14.2, notice the following lines near the bottom of the method processRequest(). System.out.println("Host: " + http.getHost()); Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com [...]... TextField tfScore; // Enter new score private int indxTextField; // Index on of the textfield private StringItem siTotal; // Running total private Command cmExit; // A Command to exit the MIDlet private Command cmUpdate; // Update score on servlet private int holeNumber = 1; // Current hole private static final int MAX_HOLES = 18; private String url = "http://www.mycgiserver.com/servlet/corej2me.Url_rewriteServlet";... s) { if (c == cmExit) { destroyApp(false); notifyDestroyed(); } else if (c == cmUpdate) // Send score for next hole { // If nothing in the text field or max scores entered if (tfScore.getString().equals("") || holeNumber > MAX_HOLES) return; else { try { // Update the score on remote server updateTotal(tfScore.getString()); // If entered the maximum, remove the // textfield from the form if (++holeNumber... http://www.simpopdf.com { fmMain.delete(indxTextField); return; } // Change the label & reset contents tfScore.setLabel("Enter score for Hole #" + holeNumber); tfScore.setString(""); } catch (Exception e) { System.err.println("Msg: " + e.toString()); } } } } /* -* Send client request Receive server response * * Client: Send score for next hole * * Server: Check for custom header 'Custom-newURL'... res.setHeader("Custom-newURL", URLwithID); } // Get the next score (parameter) passed in int nextScore = Integer.parseInt(req.getParameter("score")); // Get the ongoing total saved as part of the session // Convert to an integer "object" Integer sessionTotal = (Integer) session.getValue("sessionTotal"); // Running total from session and score passed in int runningTotal = nextScore; if (sessionTotal != null) runningTotal... - www.corej2me.com"; } } Note: You do not need to compile the servlet code to run this MIDlet The compiled code is online at the url specified in the MIDlet: "http://www.mycgiserver.com/servlet/corej2me.Url_rewriteServlet" /* -* Url_rewriteServlet.java * * Use url-rewriting to manage sessions * Keeps a running total of golf scores for a * round of 18 holes (client sends score... res.setHeader("Custom-newURL", URLwithID); } // Get the next score (parameter) passed in int nextScore = Integer.parseInt(req.getParameter("score")); // Get the ongoing total saved as part of the session // Convert to an integer "object" Integer sessionTotal = (Integer) session.getValue("sessionTotal"); // Running total from session and score passed in int runningTotal = nextScore; if (sessionTotal != null) runningTotal... from within the following MIDlets The URL for each example will contain a reference to the package "corej2me": String url = "http://www.mycgiserver.com/servlet/corej2me cookieServlet"; String url = "http://www.mycgiserver.com/servlet/corej2me getNpostServlet" String url = "http://www.mycgiserver.com/servlet/corej2me.url_ rewriteServlet"; The package name is required by mycgiserver to differentiate my servlets... Rewriting The gist of the next MIDlet is to keep track of golf scores on a remote server We would like to enter the score for each hole, one by one The server will keep a tally of the running total and report this back to the client after each score is entered Figure 14–9 shows the initial screen on the left, before submitting the first score The screen-shot on the right is the display after receiving... * future requests Any data returned is * current total for all scores entered * -*/ private void updateTotal(String score) throws IOException { HttpConnection http = null; InputStream iStrm = null; boolean ret = false; try { // When using GET, append data onto the url String completeURL = url + "?" + "score=" + score; http = (HttpConnection) Connector.open(completeURL); // ... http.close(); } } } /* -* Url_rewriteServlet.java * * Use url-rewriting to manage sessions * Keeps a running total of golf scores for a * round of 18 holes (client sends score for each * hole, one at a time) * -*/ package corej2me; // Required for mycgiserver.com 411 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com import import import . url = "http://www.mycgiserver.com/servlet/corej2me.GetNpostServlet" + "?" + "account=" + tfAcct.getString() + "&" + "password=" +. url = "http://www.mycgiserver.com/servlet/corej2me.GetNpostServlet" + "?" + "account=" + tfAcct.getString() + "&" + "password=" +. http.setRequestProperty("User-Agent", "Profile /MIDP- 1.0 Configuration/CLDC-1.0"); http.setRequestProperty("If-Modified-Since", "Mon, 16 Jul 2001 22:54:26 GMT");