標籤:
URL和URLConnection類
網路中的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,而參數通過需要通過輸出資料流來傳遞。另外還需要設定頭欄位。
URLConnection是一個協議處理器中的一個類,它是表示指向URL所指定的資源的活動串連。主要用於兩個方面,一個是與伺服器(特別是HTTP伺服器)的互動,可以用來查看伺服器發送的首部,設定串連的屬性,設定用戶端的請求的首部等。利用它也可以實現POST和PUT方法來發送資料。另一個方面是Java的協議處理器機制的一部分。所謂的協議處理器就是將處理協議的細節從處理特定資料類型中分離出,會涉及到用戶端與伺服器端的互動,如產生正確的請求格式,解釋與資料一起返回的首部等。
擷取URLConnection
根據一個已經建立的URL來通過openConnection來開啟產生一個URLConnection,雖然利用url來擷取,其實內部調用的是URLStreamHandler的openConnection,該方法是一個抽象方法,它返回的URLConnection會根據協議的類型返回,倘若是一個http url則就會返回一個HTTPURLConnection。
URL url=new URL("http://www.baidu.com");
URLConnection uc=url.openConnection();
此時該uc並沒有串連,本地與遠程主機是無法進行收發資料的,需要調用uc.connect()方法來建立串連。不過在使用getInputStream(),getHeaderField()等其它要求的時候會首先自動調用這個方法。
利用此URLConnection可以很容易讀取來自伺服器端的資料,只要其getInputStream。
URL和URLConnectin的區別
URLConnection提供了對於HTTP首部的訪問
URLConnection可以配置用戶端向伺服器端發送的請求參數即首部
URLConnection可以利用POST,PUT等要求方法與伺服器進行互動
讀取伺服器響應的首部
對於伺服器響應的首部,當然這裡都是以HTTP伺服器響應為準,可以來擷取響應中的首部欄位。
Content-type,Content-length,Content-encoding,Date,Last-modified,Expires
可以利用getContentType()來擷取資料的MIME類型,判斷字元編碼,並且以正常的格式顯示出,如
String encoding="ISO-8859-1";//HTTP預設的編碼方式URL u=new URL(url);URLConnection uc=u.openConnection(); String type=uc.getContentType(); //擷取字元編碼方式 int star=type.indexOf("charset="); if(star!=-1) encoding=type.substring(star+8); System.out.println("CharSet:"+encoding); InputStream raw=uc.getInputStream(); Reader r=new InputStreamReader(new BufferedInputStream(raw),encoding);
利用getContentLength來擷取二進位檔案大小,從而來下載檔案
URLConnection uc=url.openConnection(); String contentType=uc.getContentType(); int contentLength=uc.getContentLength(); if(contentType.startsWith("text/")||contentLength==-1) { throw new IOException("This is not a binary file"); } InputStream raw=new BufferedInputStream(uc.getInputStream()); byte[] data=new byte[contentLength]; int bytesRead=0; int offset=0; while(offset<contentLength) { bytesRead=raw.read(data, offset, contentLength); if(bytesRead==-1)break; offset+=bytesRead; } raw.close(); if(offset!=contentLength) { throw new IOException("Only read "+offset+ "bytes;Expected "+contentLength+" bytes"); } //根據URL中擷取檔案路徑的名,將擷取的流寫入到本地 String file=url.getFile(); int start=file.lastIndexOf("/"); String filename=file.substring(start+1); FileOutputStream fout=new FileOutputStream(filename); fout.write(data); fout.flush(); fout.close();
getHeaderField(String name);可以根據指定首部名來不區分大小寫擷取該名對應的值
getHeaderFieldKey(int n)和getHeaderField(int n)依此返回首部中的名和值,很有用
URL u=new URL(url);URLConnection uc=u.openConnection();for(int j=1;;j++){ String header=uc.getHeaderField(j); if(header==null)break;//skip the loop System.out.println(uc.getHeaderFieldKey(j)+":"+header);}
配置串連
所謂的配置主要就是定義了用戶端如何向伺服器做出請求。
一般用戶端在預設情況下doInput為true,表示可以接受來自伺服器端發送的資料,這些必須在URLConnection串連之前設定。如果想要利用POST和PUT進行互動就必須要設定doOutpu為true,預設是false
配置用戶端發送的HTPP首部
用戶端進行伺服器訪問的時候,有些協議需要加上首部,配置一些名值對,可以通過setRequestProperty(name,value)設定,多個值之間利用逗號隔開。
用戶端利用POST來發送資料
package com.urlconnection;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.OutputStreamWriter;import java.io.Writer;import java.net.URL;import java.net.URLConnection;//類比表單提交處理public class FormPoster { private URL url; private QueryString query=new QueryString(); //必須要保證是http協議 public FormPoster(URL url) { if(!url.getProtocol().toUpperCase().startsWith("HTTP")) { throw new IllegalArgumentException("Posting only works for http urls"); } this.url=url; } public void add(String name,String value) { query.add(name, value); } public URL getURL() { return this.url; } public InputStream post()throws IOException { URLConnection uc=url.openConnection(); uc.setDoOutput(true); Writer out=new OutputStreamWriter(uc.getOutputStream(),"ASCII"); //POST行,Content-type和Content-length是由URLConnection發送的 //只需要發送資料即可 out.write(query.toString()); out.write("\r\n\r\n"); out.flush(); out.close(); return uc.getInputStream(); } public static void main(String[] args) { // TODO Auto-generated method stub String u="http://www.baidu.com"; URL url=null; try{ url=new URL(u); }catch(IOException e) { } FormPoster poster=new FormPoster(url); poster.add("hawk", "fdafda"); poster.add("good morning", "fdafa"); try{ InputStream in=poster.post(); //讀取響應 InputStreamReader r=new InputStreamReader(in); int c; while((c=r.read())!=-1) { System.out.print((char)c); } in.close(); }catch(IOException ex) { System.err.println(ex); } }}
HTTPURLConnection
這個是一個專門操作http URL的類,繼承子URLConnection,主要有7個請求的方法,
利用setRequestMethod(String method)設定不同的要求方法,預設是get,區分大小寫
GET,從伺服器端擷取資料
POST,向伺服器端提交表單
PUT,上傳檔案至伺服器
HEAD,擷取伺服器端響應的頭部
OPTIONS,查詢服務器支援哪些要求方法
DELETE,刪除伺服器中的檔案
TRACE,伺服器返回用戶端發送的HTTP首部,用於檢測Proxy 伺服器對HTTP首部進行怎樣修改
伺服器響應的格式如下:
HTTP/1.1 200 OK
...
這個類添加了兩個方法
getResponseMessage()擷取響應碼對應的訊息,如OK
getResponseCode()擷取響應碼,如200
協議處理器
協議處理器主要就是根據URL中的協議來找到合適的協議處理器來進行用戶端與伺服器端的互動。主要涉及四個類,具體類URL,抽象類別URLConnection和URLStreamHandler,以及介面URLStreamHandlerFactory。協議處理器的流處理器總是根據指定的協議找到最適合的URLConnection
要想自己建立協議處理器,需要編寫兩個URLConnection和URLStreamHandler的子類,然後建立一個URLStreamHandlerFactory。
URLConnection子類主要處理與伺服器互動,將伺服器發送的資料轉換為InputStream,將用戶端發送的所有資料轉換為OutputStream。URLStreamHandler子類主要將URL的字串表示解析為各個部分,用這些部分來設定URL對象的各個部分,並且建立一個理解次URL協議的URLConnection。
協議處理器的基本流程如下:
1 程式先利用字串構建某一個協議的URL對象,在建立URL模式中,只會驗證是否識別URL模式,而不會對其格式的正確性進行檢查
2 建構函式利用所傳遞的參數來確定URL的協議部分,如http
3 URL()建構函式以如下方式嘗試進行找到給定的URLStreamHandler
a 如果以前使用過此協議,從緩衝中擷取URLStreamHandler
b 否則,若設定了URLStreamHandlerFactory,將此字串傳遞給工廠 www.it165.net
c 若兩個都沒有,則嘗試執行個體化一個位於java.protocol.handler.pkgs屬性列出的 protocol.Handler的URLStreamHandler
d 如果執行個體化失敗,就嘗試執行個體化一個位於sun.net.www.protocol中的protocol.Handler 的URLStreamHandler
e 如果其中一個成功了,則設定屬性欄位handler欄位。如果都不成功,則拋 出MalformedURLException異常
4 程式調用URL對象的openConnection方法
5 URL會根據協議讓URLStreamHandler返回一個適合於此URL的URLConnection
6 使用URLConnection進行與遠端資源的互動
URLStreamHandler解析URL中欄位的過程
URL(String)-->URL(URL,String)-->URL(URL,String,String)-->URLStreamHandler.parseURL()
-->URLStreamHandler.setURL()-->URL.set();
要建立立一個URLStreamHandler一般只需要修改openConnection方法即可,根據需要來修改parseURL
為每一個URLConnection子類重寫一個connect方法,該方法包含了Socket的具體建立步驟。
再利用URLStreamHandlerFactory來註冊這些流處理器
Java網路編程小結 URLConnection協議處理器