网络中的URL(Uniform Resource Locator)是统一资源定位符的简称。它表示Internet上某一资源的地址。通过URL我们可以访问Internet上的各种网络资源,比如最常见的WWW,FTP站点。 URL可以被认为是指向互联网资源的“指针”,通过URL可以获得互联网资源相关信息,包括获得URL的InputStream对象获取资源的信息,以及一个到URL所引用远程对象的连接URLConnection。 URLConnection对象可以向所代表的URL发送请求和读取URL的资源。通常,创建一个和URL的连接,需要如下几个步骤:
- 创建URL对象,并通过调用openConnection方法获得URLConnection对象;
- 设置URLConnection参数和普通请求属性;
- 向远程资源发送请求;
- 远程资源变为可用,程序可以访问远程资源的头字段和通过输入流来读取远程资源返回的信息。
这里需要重点讨论一下第三步:如果只是发送GET方式请求,使用connect方法建立和远程资源的连接即可;如果是需要发送POST方式的请求,则需要获取URLConnection对象所对应的输出流来发送请求。这里需要注意的是,由于GET方法的参数传递方式是将参数显式追加在地址后面,那么在构造URL对象时的参数就应当是包含了参数的完整URL地址,而在获得了URLConnection对象之后,就直接调用connect方法即可发送请求。而POST方法传递参数时仅仅需要页面URL,而参数通过需要通过输出流来传递。
package com.wa.axis2.test; import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; import org.junit.Test; public class Upload { @Test public void upload(){ try { URL url=new URL("http://localhost:8090/audit/UploadFileHttpServlet?name=hello"); HttpURLConnection urlConnection=(HttpURLConnection) url.openConnection(); urlConnection.setDoInput(true); urlConnection.setDoOutput(true); urlConnection.setUseCaches(false); urlConnection.setRequestProperty("Content-Type", "application/octet-stream"); urlConnection.setRequestProperty("ReturnFileUploadPath", "D://test//a.txt"); File file=new File("E:\\aa.txt"); int len=0; byte[] by=new byte[1024*1024]; BufferedInputStream bi=new BufferedInputStream(new FileInputStream(file)); while((len=bi.read(by))!=-1){ urlConnection.getOutputStream().write(by, 0, len); } // 获得响应状态 int responseCode = urlConnection.getResponseCode(); if (HttpURLConnection.HTTP_OK == responseCode) { // 当正确响应时处理数据 System.out.println(""); System.out.println("Http Response OK..."); // 处理响应流,必须与服务器响应流输出的编码一致 StringBuffer responseBuffer = new StringBuffer(); String readLine; BufferedReader responseReader = new BufferedReader(new InputStreamReader( urlConnection.getInputStream(), "utf-8")); while ((readLine = responseReader.readLine()) != null) { responseBuffer.append(readLine).append("n"); } System.out.println("Http Response:" + responseBuffer); responseReader.close(); } bi.close(); } catch (Exception e) { e.printStackTrace(); } } }
服务器servlet代码如下:
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String name = request.getParameter("name"); String path=request.getHeader("ReturnFileUploadPath"); System.out.println(path); File file=new File(path); if(!file.exists()){ file.getParentFile().mkdirs(); } //读取发送来的文件并且保存到本地 BufferedOutputStream bo=new BufferedOutputStream(new FileOutputStream(file)); int len=0; byte[] by=new byte[1024*1024]; while((len=request.getInputStream().read(by))!=-1){ bo.write(by, 0, len); } bo.flush(); bo.close(); response.setContentType("text/plain; charset=UTF-8"); response.setCharacterEncoding("UTF-8"); response.getWriter().write("It is ok!"); }
注意事项;
总结:a:) HttpURLConnection的connect()函数,实际上只是建立了一个与服务器的tcp连接,并没有实际发送http请求。
无论是post还是get,http请求实际上直到HttpURLConnection的getInputStream()这个函数里面才正式发送出去。
b:) 在用POST方式发送URL请求时,URL请求参数的设定顺序是重中之重, 对connection对象的一切配置(那一堆set函数) 都必须要在connect()函数执行之前完成。而对outputStream的写操作,又必须要在inputStream的读操作之前。 这些顺序实际上是由http请求的格式决定的。
如果inputStream读操作在outputStream的写操作之前,会抛出例外:
java.net.ProtocolException: Cannot write output after reading input.......
c:) http请求实际上由两部分组成,
一个是http头,所有关于此次http请求的配置都在http头里面定义,所以在服务端需要使用getHeader来获取参数,request.getHeader("ReturnFileUploadPath");
一个是正文content。
connect()函数会根据HttpURLConnection对象的配置值生成http头部信息,因此在调用connect函数之前, 就必须把所有的配置准备好。
d:) 在http头后面紧跟着的是http请求的正文,正文的内容是通过outputStream流写入的,
实际上outputStream不是一个网络流,充其量是个字符串流,往里面写入的东西不会立即发送到网络,
而是存在于内存缓冲区中,待outputStream流关闭时,根据输入的内容生成http正文。
至此,http请求的东西已经全部准备就绪。在getInputStream()函数调用的时候,就会把准备好的http请求 正式发送到服务器了,然后返回一个输入流,用于读取服务器对于此次http请求的返回信息。由于http 请求在getInputStream的时候已经发送出去了(包括http头和正文),因此在getInputStream()函数 之后对connection对象进行设置(对http头的信息进行修改)或者写入outputStream(对正文进行修改) 都是没有意义的了,执行这些操作会导致异常的发生。