HTTP 協議多是如今 Internet 上使用得最多、最重要的協議了,愈來愈多的 Java 應用程序須要直接經過 HTTP 協議來訪問網絡資源。java
雖然在 JDK 的 java.net 包中已經提供了訪問 HTTP 協議的基本功能,可是對於大部分應用程序來講,JDK 庫自己提供的功能還不夠豐富和靈活。HttpClient 用來提供高效的、最新的、功能豐富的支持 HTTP 協議的客戶端編程工具包,而且它支持 HTTP 協議最新的版本和建議。apache
通常的狀況下咱們都是使用Chrome或者其餘瀏覽器來訪問一個WEB服務器,用來瀏覽頁面查看信息或者提交一些數據、文件上傳下載等等。所訪問的這些頁面有的僅僅是一些普通的頁面,有的須要用戶登陸後方可以使用,或者須要認證以及是一些經過加密方式傳輸,例如HTTPS。目前咱們使用的瀏覽器處理這些狀況都不會構成問題。可是一旦咱們有需求不經過瀏覽器來訪問服務器的資源呢?那該怎麼辦呢?編程
下面以本地客戶端發起文件的上傳、下載爲例作個小Demo。HttpClient有兩種形式,一種是org.apache.http下的,一種是org.apache.commons.httpclient.HttpClient。數組
文件上傳可使用兩種方式實現,一種是PostMethod方式,一種是HttpPost方式。二者的處理大同小異。PostMethod是使用FileBody將文件包裝流包裝起來,HttpPost是使用FilePart將文件流包裝起來。在傳遞文件流給服務端的時候,均可以同時傳遞其餘的參數。瀏覽器
將文件封裝到FilePart中,放入Part數組,同時,其餘參數能夠放入StringPart中,這裏沒有寫,只是單純的將參數以setParameter的方式進行設置。此處的HttpClient是org.apache.commons.httpclient.HttpClient。緩存
1 public void upload(String localFile){ 2 File file = new File(localFile); 3 PostMethod filePost = new PostMethod(URL_STR); 4 HttpClient client = new HttpClient(); 5 6 try { 7 // 經過如下方法能夠模擬頁面參數提交 8 filePost.setParameter("userName", userName); 9 filePost.setParameter("passwd", passwd); 10 11 Part[] parts = { new FilePart(file.getName(), file) }; 12 filePost.setRequestEntity(new MultipartRequestEntity(parts, filePost.getParams())); 13 14 client.getHttpConnectionManager().getParams().setConnectionTimeout(5000); 15 16 int status = client.executeMethod(filePost); 17 if (status == HttpStatus.SC_OK) { 18 System.out.println("上傳成功"); 19 } else { 20 System.out.println("上傳失敗"); 21 } 22 } catch (Exception ex) { 23 ex.printStackTrace(); 24 } finally { 25 filePost.releaseConnection(); 26 } 27 }
記得搞完以後,要經過releaseConnection釋放鏈接。 服務器
這種方式,與上面相似,只不過變成了FileBody。上面的Part數組在這裏對應HttpEntity。此處的HttpClient是org.apache.http.client.methods下的。網絡
1 public void upload(String localFile){ 2 CloseableHttpClient httpClient = null; 3 CloseableHttpResponse response = null; 4 try { 5 httpClient = HttpClients.createDefault(); 6 7 // 把一個普通參數和文件上傳給下面這個地址 是一個servlet 8 HttpPost httpPost = new HttpPost(URL_STR); 9 10 // 把文件轉換成流對象FileBody 11 FileBody bin = new FileBody(new File(localFile)); 12 13 StringBody userName = new StringBody("Scott", ContentType.create( 14 "text/plain", Consts.UTF_8)); 15 StringBody password = new StringBody("123456", ContentType.create( 16 "text/plain", Consts.UTF_8)); 17 18 HttpEntity reqEntity = MultipartEntityBuilder.create() 19 // 至關於<input type="file" name="file"/> 20 .addPart("file", bin) 21 22 // 至關於<input type="text" name="userName" value=userName> 23 .addPart("userName", userName) 24 .addPart("pass", password) 25 .build(); 26 27 httpPost.setEntity(reqEntity); 28 29 // 發起請求 並返回請求的響應 30 response = httpClient.execute(httpPost); 31 32 System.out.println("The response value of token:" + response.getFirstHeader("token")); 33 34 // 獲取響應對象 35 HttpEntity resEntity = response.getEntity(); 36 if (resEntity != null) { 37 // 打印響應長度 38 System.out.println("Response content length: " + resEntity.getContentLength()); 39 // 打印響應內容 40 System.out.println(EntityUtils.toString(resEntity, Charset.forName("UTF-8"))); 41 } 42 43 // 銷燬 44 EntityUtils.consume(resEntity); 45 }catch (Exception e){ 46 e.printStackTrace(); 47 }finally { 48 try { 49 if(response != null){ 50 response.close(); 51 } 52 } catch (IOException e) { 53 e.printStackTrace(); 54 } 55 56 try { 57 if(httpClient != null){ 58 httpClient.close(); 59 } 60 } catch (IOException e) { 61 e.printStackTrace(); 62 } 63 } 64 }
不管客戶端是哪一種上傳方式,服務端的處理都是同樣的。在經過HttpServletRequest得到參數以後,把獲得的Item進行分類,分爲普通的表單和File表單。 app
經過ServletFileUpload 能夠設置上傳文件的大小及編碼格式等。tcp
總之,服務端的處理是把獲得的參數當作HTML表單進行處理的。
1 public void processUpload(HttpServletRequest request, HttpServletResponse response){ 2 File uploadFile = new File(uploadPath); 3 if (!uploadFile.exists()) { 4 uploadFile.mkdirs(); 5 } 6 7 System.out.println("Come on, baby ......."); 8 9 request.setCharacterEncoding("utf-8"); 10 response.setCharacterEncoding("utf-8"); 11 12 //檢測是否是存在上傳文件 13 boolean isMultipart = ServletFileUpload.isMultipartContent(request); 14 15 if(isMultipart){ 16 DiskFileItemFactory factory = new DiskFileItemFactory(); 17 18 //指定在內存中緩存數據大小,單位爲byte,這裏設爲1Mb 19 factory.setSizeThreshold(1024*1024); 20 21 //設置一旦文件大小超過getSizeThreshold()的值時數據存放在硬盤的目錄 22 factory.setRepository(new File("D:\\temp")); 23 24 // Create a new file upload handler 25 ServletFileUpload upload = new ServletFileUpload(factory); 26 27 // 指定單個上傳文件的最大尺寸,單位:字節,這裏設爲50Mb 28 upload.setFileSizeMax(50 * 1024 * 1024); 29 30 //指定一次上傳多個文件的總尺寸,單位:字節,這裏設爲50Mb 31 upload.setSizeMax(50 * 1024 * 1024); 32 upload.setHeaderEncoding("UTF-8"); 33 34 List<FileItem> items = null; 35 36 try { 37 // 解析request請求 38 items = upload.parseRequest(request); 39 } catch (FileUploadException e) { 40 e.printStackTrace(); 41 } 42 43 if(items!=null){ 44 //解析表單項目 45 Iterator<FileItem> iter = items.iterator(); 46 while (iter.hasNext()) { 47 FileItem item = iter.next(); 48 49 //若是是普通表單屬性 50 if (item.isFormField()) { 51 //至關於input的name屬性 <input type="text" name="content"> 52 String name = item.getFieldName(); 53 54 //input的value屬性 55 String value = item.getString(); 56 57 System.out.println("屬性:" + name + " 屬性值:" + value); 58 } 59 //若是是上傳文件 60 else { 61 //屬性名 62 String fieldName = item.getFieldName(); 63 64 //上傳文件路徑 65 String fileName = item.getName(); 66 fileName = fileName.substring(fileName.lastIndexOf("/") + 1);// 得到上傳文件的文件名 67 68 try { 69 item.write(new File(uploadPath, fileName)); 70 } catch (Exception e) { 71 e.printStackTrace(); 72 } 73 } 74 } 75 } 76 } 77 78 response.addHeader("token", "hello"); 79 }
服務端在處理以後,能夠在Header中設置返回給客戶端的簡單信息。若是返回客戶端是一個流的話,流的大小必須提早設置!
response.setContentLength((int) file.length());
文件的下載可使用HttpClient的GetMethod實現,還可使用HttpGet方式、原始的HttpURLConnection方式。
此處的HttpClient是org.apache.commons.httpclient.HttpClient。
1 public void downLoad(String remoteFileName, String localFileName) { 2 HttpClient client = new HttpClient(); 3 GetMethod get = null; 4 FileOutputStream output = null; 5 6 try { 7 get = new GetMethod(URL_STR); 8 get.setRequestHeader("userName", userName); 9 get.setRequestHeader("passwd", passwd); 10 get.setRequestHeader("fileName", remoteFileName); 11 12 int i = client.executeMethod(get); 13 14 if (SUCCESS == i) { 15 System.out.println("The response value of token:" + get.getResponseHeader("token")); 16 17 File storeFile = new File(localFileName); 18 output = new FileOutputStream(storeFile); 19 20 // 獲得網絡資源的字節數組,並寫入文件 21 output.write(get.getResponseBody()); 22 } else { 23 System.out.println("DownLoad file occurs exception, the error code is :" + i); 24 } 25 } catch (Exception e) { 26 e.printStackTrace(); 27 } finally { 28 try { 29 if(output != null){ 30 output.close(); 31 } 32 } catch (IOException e) { 33 e.printStackTrace(); 34 } 35 36 get.releaseConnection(); 37 client.getHttpConnectionManager().closeIdleConnections(0); 38 } 39 }
此處的HttpClient是org.apache.http.client.methods下的。
1 public void downLoad(String remoteFileName, String localFileName) { 2 DefaultHttpClient httpClient = new DefaultHttpClient(); 3 OutputStream out = null; 4 InputStream in = null; 5 6 try { 7 HttpGet httpGet = new HttpGet(URL_STR); 8 9 httpGet.addHeader("userName", userName); 10 httpGet.addHeader("passwd", passwd); 11 httpGet.addHeader("fileName", remoteFileName); 12 13 HttpResponse httpResponse = httpClient.execute(httpGet); 14 HttpEntity entity = httpResponse.getEntity(); 15 in = entity.getContent(); 16 17 long length = entity.getContentLength(); 18 if (length <= 0) { 19 System.out.println("下載文件不存在!"); 20 return; 21 } 22 23 System.out.println("The response value of token:" + httpResponse.getFirstHeader("token")); 24 25 File file = new File(localFileName); 26 if(!file.exists()){ 27 file.createNewFile(); 28 } 29 30 out = new FileOutputStream(file); 31 byte[] buffer = new byte[4096]; 32 int readLength = 0; 33 while ((readLength=in.read(buffer)) > 0) { 34 byte[] bytes = new byte[readLength]; 35 System.arraycopy(buffer, 0, bytes, 0, readLength); 36 out.write(bytes); 37 } 38 39 out.flush(); 40 41 } catch (IOException e) { 42 e.printStackTrace(); 43 } catch (Exception e) { 44 e.printStackTrace(); 45 }finally{ 46 try { 47 if(in != null){ 48 in.close(); 49 } 50 } catch (IOException e) { 51 e.printStackTrace(); 52 } 53 54 try { 55 if(out != null){ 56 out.close(); 57 } 58 } catch (IOException e) { 59 e.printStackTrace(); 60 } 61 } 62 }
1 public void download3(String remoteFileName, String localFileName) { 2 FileOutputStream out = null; 3 InputStream in = null; 4 5 try{ 6 URL url = new URL(URL_STR); 7 URLConnection urlConnection = url.openConnection(); 8 HttpURLConnection httpURLConnection = (HttpURLConnection) urlConnection; 9 10 // true -- will setting parameters 11 httpURLConnection.setDoOutput(true); 12 // true--will allow read in from 13 httpURLConnection.setDoInput(true); 14 // will not use caches 15 httpURLConnection.setUseCaches(false); 16 // setting serialized 17 httpURLConnection.setRequestProperty("Content-type", "application/x-java-serialized-object"); 18 // default is GET 19 httpURLConnection.setRequestMethod("POST"); 20 httpURLConnection.setRequestProperty("connection", "Keep-Alive"); 21 httpURLConnection.setRequestProperty("Charsert", "UTF-8"); 22 // 1 min 23 httpURLConnection.setConnectTimeout(60000); 24 // 1 min 25 httpURLConnection.setReadTimeout(60000); 26 27 httpURLConnection.addRequestProperty("userName", userName); 28 httpURLConnection.addRequestProperty("passwd", passwd); 29 httpURLConnection.addRequestProperty("fileName", remoteFileName); 30 31 // connect to server (tcp) 32 httpURLConnection.connect(); 33 34 in = httpURLConnection.getInputStream();// send request to 35 // server 36 File file = new File(localFileName); 37 if(!file.exists()){ 38 file.createNewFile(); 39 } 40 41 out = new FileOutputStream(file); 42 byte[] buffer = new byte[4096]; 43 int readLength = 0; 44 while ((readLength=in.read(buffer)) > 0) { 45 byte[] bytes = new byte[readLength]; 46 System.arraycopy(buffer, 0, bytes, 0, readLength); 47 out.write(bytes); 48 } 49 50 out.flush(); 51 }catch(Exception e){ 52 e.printStackTrace(); 53 }finally{ 54 try { 55 if(in != null){ 56 in.close(); 57 } 58 } catch (IOException e) { 59 e.printStackTrace(); 60 } 61 62 try { 63 if(out != null){ 64 out.close(); 65 } 66 } catch (IOException e) { 67 e.printStackTrace(); 68 } 69 } 70 }
儘管客戶端的處理方式不一樣,可是服務端是同樣的。
1 public void processDownload(HttpServletRequest request, HttpServletResponse response){ 2 int BUFFER_SIZE = 4096; 3 InputStream in = null; 4 OutputStream out = null; 5 6 System.out.println("Come on, baby ......."); 7 8 try{ 9 request.setCharacterEncoding("utf-8"); 10 response.setCharacterEncoding("utf-8"); 11 response.setContentType("application/octet-stream"); 12 13 String userName = request.getHeader("userName"); 14 String passwd = request.getHeader("passwd"); 15 String fileName = request.getHeader("fileName"); 16 17 System.out.println("userName:" + userName); 18 System.out.println("passwd:" + passwd); 19 System.out.println("fileName:" + fileName); 20 21 //能夠根據傳遞來的userName和passwd作進一步處理,好比驗證請求是否合法等 23 File file = new File(downloadPath + "\\" + fileName); 24 response.setContentLength((int) file.length()); 25 response.setHeader("Accept-Ranges", "bytes"); 26 27 int readLength = 0; 28 29 in = new BufferedInputStream(new FileInputStream(file), BUFFER_SIZE); 30 out = new BufferedOutputStream(response.getOutputStream()); 31 32 byte[] buffer = new byte[BUFFER_SIZE]; 33 while ((readLength=in.read(buffer)) > 0) { 34 byte[] bytes = new byte[readLength]; 35 System.arraycopy(buffer, 0, bytes, 0, readLength); 36 out.write(bytes); 37 } 38 39 out.flush(); 40 41 response.addHeader("token", "hello 1"); 42 43 }catch(Exception e){ 44 e.printStackTrace(); 45 response.addHeader("token", "hello 2"); 46 }finally { 47 if (in != null) { 48 try { 49 in.close(); 50 } catch (IOException e) { 51 } 52 } 53 if (out != null) { 54 try { 55 out.close(); 56 } catch (IOException e) { 57 } 58 } 59 } 60 }
HttpClient最基本的功能就是執行Http方法。一個Http方法的執行涉及到一個或者多個Http請求/Http響應的交互,一般這個過程都會自動被HttpClient處理,對用戶透明。用戶只須要提供Http請求對象,HttpClient就會將http請求發送給目標服務器,而且接收服務器的響應,若是http請求執行不成功,httpclient就會拋出異常。因此在寫代碼的時候注意finally的處理。
全部的Http請求都有一個請求列(request line),包括方法名、請求的URI和Http版本號。HttpClient支持HTTP/1.1這個版本定義的全部Http方法:GET,HEAD,POST,PUT,DELETE,TRACE和OPTIONS。上面的上傳用到了Post,下載是Get。
目前來講,使用org.apache.commons.httpclient.HttpClient多一些。看本身了~
-------------------------------------------------------------------------------
若是您看了本篇博客,以爲對您有所收穫,請點擊右下角的 [推薦]
若是您想轉載本博客,請註明出處
若是您對本文有意見或者建議,歡迎留言
感謝您的閱讀,請關注個人後續博客