Now, although it is indeed rather straightforward to work out how to send POST requests to a server, I found (the hard way) that there are certain "minor details" that are best not forgotten.
I have thus decided to post here a brief example of how to send a request to a server, using a form-encoded body, so that either a JSP or a servlet can retriever the parameters, but one can benefit from the many advantages of POSTing, as oppposed to GETting.
The source code follows, I believe it is reasonably self-explanatory and comments should guide even the most novice reader through, but please do let me know if you feel that this is still too cryptic:
private void OpenConnection(String server) throws java.io.IOException { // TODO: the actual "resource" part of the URL (/test in this case) // should be either passed as a parameter or obtained at application // level (maybe even set up at runtime). // To test this code, I have written the simple Servlet below, however // this would also work with a JSP page that echoes back the contents // in text/plain format for the midlet to display. // String url = "http://"+server+"/test"; byte[] data = null; InputStream istrm = null; HttpConnection http = (HttpConnection)Connector.open(url); http.setRequestMethod(HttpConnection.POST); // This allows a JSP page to process the parameters correctly // This format (or content type) is the same as when forms are // submitted from a web page. http.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); // You may want to indicate to the server side (eg servlet) that // this request is coming from a specific application. This would // allow generation of appropriate format for the content. http.setRequestProperty("User-Agent", "HttpMidlet/0.2"); // You can send any custom property as part of the HTTP header // This would matter for the "infrastructure" code, as opposed // to "body parameters" that would matter to the application // (eg, user=marco) http.setRequestProperty("Custom-Property", "MyCustomProperty/1.0; AnotherProperty/debug_0.1"); // You MUST create the body of the post BEFORE actually opening // the stream, otherwise you won't be able to set the length of // the request (see next step). // In this example, I am sending coordinates to a mapping server String msg = "x="+location.getX()+"&y="+location.getY(); // THIS is important! without it a JSP won't process the POST data // it would also appear that CASE MATTERS (using "Content-Length" -note // the capital 'L'- caused my servlet to return -1 from the // HttpServletRequest.getContentLenght() method http.setRequestProperty("Content-length", ""+msg.getBytes().length); // After this point, any call to http.setRequestProperty() will // cause an IOException OutputStream out = http.openOutputStream(); out.write(msg.getBytes()); out.flush(); if (http.getResponseCode() == HttpConnection.HTTP_OK) { int len = (int)http.getLength(); istrm = http.openInputStream(); if (istrm == null) { log("Cannot open stream - aborting"); throw new IOException("Cannot open HTTP InputStream, aborting"); } if (len != -1) { data = new byte[len]; int bytesRead = istrm.read(data); addProgressMsg("Read "+bytesRead+" bytes"); } else { ByteArrayOutputStream bo = new ByteArrayOutputStream(); int ch; int count = 0; // This is obviously not particularly efficient // You may want to use a byte[] buffer to read bytes in chunks while ((ch = istrm.read()) != -1) { bo.write(ch); count++; } data = bo.toByteArray(); bo.close(); addProgressMsg("Read "+count+" bytes"); } response = new String(data); addProgressMsg("finished"); } else { log("Response: "+http.getResponseCode()+", "+http.getResponseMessage()); response = null; addProgressMsg("failed: "+http.getResponseMessage()); } // This is critical, unless you close the HTTP connection, the application // will either be consuming needlessly resources or, even worse, sending // 'keep-alive' data, causing your user to foot unwanted bills! http.close(); }
To test this code, all that is required is a simple Serlvet that runs, for example, in an Apache Tomcat JSP container:
public class ConnectivityDiag extends HttpServlet { private static final String REVISION = "0.0.04"; private static Logger log; public ConnectivityDiag() { if (log == null) { log = Logger.getLogger(getClass().getName()); BasicConfigurator.configure(); } } public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { doProcessRequest(req, res); }
public void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { doProcessRequest(req, res); } public void doProcessRequest(HttpServletRequest req, HttpServletResponse res) { BufferedReader reader = null; Writer writer = null; try { // Note this call seems to be case-sensitive // if the midlet does not set exactly "Content-length" // as the property, -1 will be returned int len = req.getContentLength(); String contentType = req.getContentType(); log.debug("Len: " + len); log.debug("Type: "+contentType); int bytesRead = 0; String remoteHost = req.getRemoteHost(); String userAgent = req.getHeader("user-agent"); log.info("Accessed at " + (new Date()) + " from " + remoteHost + ", using " + userAgent); // This simply echoes the parameters back to the client. // A JSP would use these in a tag // and the ${param} macro. ArrayList strings = new ArrayList(); Enumeration e = req.getParameterNames(); while (e.hasMoreElements()) { String param = (String)e.nextElement(); String value = (String)req.getParameter(param); strings.add(param+" = "+value); } res.setContentType("text/plain"); // This is a custom property, that the remote client // could query res.setHeader("Sent-at", new Date().toString()); writer = res.getWriter(); writer.write("Diagnostic servlet - Rev. "+REVISION); writer.write("\nBytes received: " + len); writer.write("\nFrom: " + remoteHost); writer.write("\nUsing: " + userAgent); writer.write("\n=== Parameters ===\n"); for(String s:strings) { writer.write(s); writer.write('\n'); } writer.write("=== Parameters end here ===\n"); writer.flush(); } catch (IOException e) { log.error(e.getMessage()); } finally { try { if (reader != null) reader.close(); if (writer != null) writer.close(); } catch (IOException ex) { log.error(ex.getMessage()); } } } }
Link: http://codetrips.blogspot.com/2007/04/http-post-from-j2me-midlet.html
No comments:
Post a Comment