最常用的HTTP请求无非是get和post。get请求可以获得静态页面,也可以将参数放在URL字串后面,传递给servlet。post和get的区别在于post的参数不是放在URL字串中,而是放在http请求的文本中。
HttpurLConection可用于Java中发起这两个要求,了解这些要求对于理解soap和编写servlet的自动测试代码非常有帮助。
以下代码简要描述了如何使用HttpurLConection发起这两个请求,以及传输参数的方法:
public class HttpInvoker { public static final String GET_URL = " http://localhost:8080/welcome1 " ; public static final String POST_URL = " http://localhost:8080/welcome1 " ; public static void readContentFromGet() throws IOException { // 拼凑get请求的URL字串,使用URLEncoder.encode编码特殊和不可见的字符 String getURL = GET_URL + " ?username= " + URLEncoder.encode( " fat man " , " utf-8 " ); URL getUrl = new URL(getURL); // 打开连接,根据拼凑URL,URL.根据URL的类型,openconection函数, // 回到URLConection子类的不同对象,这里URL是http,因此,HttpurLConection实际返回 HttpURLConnection connection = (HttpURLConnection) getUrl .openConnection(); // 进行连接,但实际上是get request应该在下一句conection中.getInputStream()函数只会真正发送到 // 服务器 connection.connect(); // 获取输入流,用Reader读取 BufferedReader reader = new BufferedReader( new InputStreamReader( connection.getInputStream())); System.out.println( " ============================= " ); System.out.println( " Contents of get request " ); System.out.println( " ============================= " ); String lines; while ((lines = reader.readLine()) != null ) { System.out.println(lines); } reader.close(); // 断开连接 connection.disconnect(); System.out.println( " ============================= " ); System.out.println( " Contents of get request ends " ); System.out.println( " ============================= " ); } public static void readContentFromPost() throws IOException { // Post请求的url,与get不同的是,不需要带参数 URL postUrl = new URL(POST_URL); // 打开连接 HttpURLConnection connection = (HttpURLConnection) postUrl .openConnection(); // Output to the connection. Default is // false, set to true because post // method must write something to the // connection // 设置是否输出到connection,因为这是post请求,参数要放在 // http正文中,因此,需要设置为true connection.setDoOutput( true ); // Read from the connection. Default is true. connection.setDoInput( true ); // Set the post method. Default is GET connection.setRequestMethod( " POST " ); // Post cannot use caches // Post 请求不能使用缓存 connection.setUseCaches( false ); // This method takes effects to // every instances of this class. // URLConnection.static函数是static函数,setfollowredirects。作用于所有URLConection对象。 // connection.setFollowRedirects(true); // This methods only // takes effacts to this // instance. // URLConnection.setinstancefollowredirects是成员函数,仅用于当前函数 connection.setInstanceFollowRedirects( true ); // Set the content type to urlencoded, // because we will write // some URL-encoded content to the // connection. Settings above must be set before connect! // 配置本连接的Contentent-type,application配置x-www-form-urlencoded // 意思是文本是urlencoded编码的form参数,我们可以看到URLEncoder用于正文内容.encode // 进行编码 connection.setRequestProperty( " Content-Type " , " application/x-www-form-urlencoded " ); // 从posturl连接.openConnection()至此配置必须在connect之前完成, // 注意connection.getoutputstream将隐含connect。 connection.connect(); DataOutputStream out = new DataOutputStream(connection .getOutputStream()); // The URL-encoded contend // 正文,事实上,正文内容与get的URL相结合。后参数字符串一致 String content = " firstname= " + URLEncoder.encode( " 一个大肥人 " , " utf-8 " ); // DataOutputStream.writebytes将字符串中的16位unicode字符以8位字符的形式写入流中 out.writeBytes(content); out.flush(); out.close(); // flush and close BufferedReader reader = new BufferedReader( new InputStreamReader( connection.getInputStream())); String line; System.out.println( " ============================= " ); System.out.println( " Contents of post request " ); System.out.println( " ============================= " ); while ((line = reader.readLine()) != null ) { System.out.println(line); } System.out.println( " ============================= " ); System.out.println( " Contents of post request ends " ); System.out.println( " ============================= " ); reader.close(); connection.disconnect(); } /** *//** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub try { readContentFromGet(); readContentFromPost(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
上面的 readContentFromGet()函数产生了一个get请求,传递给servletusername参数,值为“fat man"。
readContentFromPost()函数产生post请求,传递给servletfirstname参数,值为“大肥人”。
HttpURLConnection.事实上,conect函数只与服务器建立了tcp连接,并没有实际发送http请求。http请求实际上直到post和get
HttpURLConnection .getInputStream()这个函数刚刚正式发出。
在 readContentFromPost在()中,顺序是最重要的,所有配置(那堆set函数)都必须在conect()函数执行之前完成。outputstream的写作操作必须在inputstream的读取操作之前进行。这些顺序实际上是由http请求的格式决定的。
http请求实际上由两部分组成,一部分是http头,http请求的所有配置都定义在http头中,另一部分是文本content。在conect()函数中,htttp头将根据httpurlconection对象的配置值生成。因此,在调用conect函数之前,必须准备好所有的配置。
然后http头是http请求的文本。文本的内容通过outputstream写入。事实上,outputstream不是一个网络流。充其量,它是一个字符串流。写入其中的内容不会立即发送到网络,而是在流关闭后根据输入内容生成http文本。
到目前为止,http要求的东西已经准备好了。调用getinputstream()函数时,准备好的http请求将正式发送到服务器,然后返回输入流,读取服务器对http请求的返回信息。由于http请求已经在getinputstream时发送(包括http头和文本),因此在getinputstream()函数后设置conection对象(修改http头的信息)或写入outputstream(修改文本)是没有意义的,执行这些操作会导致异常
上一节说,post请求的outputstream实际上不是网络流,而是写入内存。只有在getinputstream中,写道流中的内容才能真正作为文本,并根据之前的配置生成http request头合并成真正的http request,直到那时,它才真正发送到服务器。
HttpURLConnection.setchunkedstreamingmode函数可以改变此模式。设置chunkedstreamingmode后,不再等待outputstream关闭,生成完整的httprequest一次发送,而是先发送httprequest头,文本内容是通过网络流实时传输到服务器。事实上,它并没有告诉服务器http文本的长度,这种模式适用于向服务器传输较大或不易获取长度的数据,如文件。事实上,它并没有告诉服务器http文本的长度,这种模式适用于向服务器传输较大或不易获取长度的数据,如文件。
public static void readContentFromChunkedPost() throws IOException { URL postUrl = new URL(POST_URL); HttpURLConnection connection = (HttpURLConnection) postUrl .openConnection(); connection.setDoOutput( true ); connection.setDoInput( true ); connection.setRequestMethod( " POST " ); connection.setUseCaches( false ); connection.setInstanceFollowRedirects( true ); connection.setRequestProperty( " Content-Type " , " application/x-www-form-urlencoded " ); /** //* * 与readContentfromPost()最大的不同,设置块大小为5字节 */ connection.setChunkedStreamingMode( 5 ); connection.connect(); /** //* * 注意,在readContentfromPost()中,下面的getoutstream函数工作模式是不同的 * 该函数在readcontentfrompost()中仍在准备httpp request,没有向服务器发送任何数据 * 在这里,由于Chunkedstreamingmode的设置,getoutputstream函数将根据connect之前的配置进行配置 * 生成http request头,先发送到服务器。 */ DataOutputStream out = new DataOutputStream(connection .getOutputStream()); String content = " firstname= " + URLEncoder.encode( " 一个大肥人 " + " " + " asdfasfdasfasdfaasdfasdfasdfdasfs " , " utf-8 " ); out.writeBytes(content); out.flush(); out.close(); // 此时,服务器已经收到了完整的http request,在readcontentfrompost()函数中,http请求需要等到下一个服务器。 BufferedReader reader = new BufferedReader( new InputStreamReader( connection.getInputStream())); out.flush(); out.close(); // flush and close String line; System.out.println( " ============================= " ); System.out.println( " Contents of post request " ); System.out.println( " ============================= " ); while ((line = reader.readLine()) != null ) { System.out.println(line); } System.out.println( " ============================= " ); System.out.println( " Contents of post request ends " ); System.out.println( " ============================= " ); reader.close(); connection.disconnect(); }