1. 程式人生 > >java網路程式設計-HTTP和URLConnection

java網路程式設計-HTTP和URLConnection

HTTP和URLConnection

標籤(空格分隔): java網路程式設計

HTTP

get請求是一個空行結束,也就是\r\n\r\n

CookieManager

啟用cookie:

CookieManager manager = new CookieManager();
CookieHandler.setDefault(manager);

接受策略:

CookiePolicy.ACCEPT_ALL接受所有cookie
CookiePolicy.ACCEPT_NONE不接受任何cookie
CookiePolicy.ACCEPT_ORIGINAL_SERVER只接受第一坊cookie

使用:

manager.setCookiePolicy(CookiePolicy.ACCEPT_ORIGINAL_SERVER)

自定義:實現CookiePolicy介面:

public boolean  shouldAccept(URI uri, HttpCookie cookie)

例如:

 public class NoGovernmentCookies implements CookiePolicy{
     @overide
     public boolean shouldAccept(URI uri, HttpCookie cookie){
         if
(uri.getAuthority().toLowerCase().endsWith(".gov") || cooke.getDomain().toLowerCase().endsWith(".gov")){ return false;//阻止 } } return true; } }

URLConnection

是一個抽象類,表示指向URL指定資源的活動連線
使用該類的一般步驟(不一定全部執行):

1. 構造一個URL物件
2. 呼叫openConnection建立URLConnection物件
3. 配置URLConnection
3. 讀取首部欄位
5. 獲取輸入流並讀取資料
6. 獲取輸出流並寫入資料
7. 關閉連線

第一次構造URLConnection時,是沒有socket連線這兩個主機,connect()方法在本地和遠端主機之間建立一個連線。同時對於getInputStream(),getContent(),getHeaderField()和其他要求開啟連線的方法,如果未開啟,會自動呼叫connect()
案例:用URLConnection下載一個WEB頁面:

public class SourceViewer2 {
public static void main(String[] args) {
    if (args.length > 0) {
        try {
            URL u = new URL(args[0]);
            URLConnection uc = u.openConnection();
            try (InputStream raw = uc.getInputStream()) {
                InputStream buffer = new BufferedInputStream(raw);
                Reader reader = new InputStreamReader(buffer);
                int c;
                while ((c = reader.read()) != -1) {
                    System.out.println((char) c);
                }
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

}

URLConnection和URL的區別

URLConnection 提供了對HTTP首部的訪問
可以配置伺服器的請求引數
可以向伺服器寫入資料

讀取首部

public String getContentType()

返回響應主體的MIME型別(可能包括編碼型別,因此可以按指定的編碼方式解碼)

public int getContentLength()

內容有多少位元組,如果沒有該首部就返回-1,如果位元組數超出int範圍應該使用:

public long getContentLengthLong();//java7

示例:下載二進位制檔案

public class BinarySaver {
public static void main(String[] args) {
    for (int i = 0; i < args.length; i++) {
        try {
            URL root = new URL(args[i]);
            saveBinaryFile(root);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
private static void saveBinaryFile(URL u) throws IOException {
    URLConnection uc = u.openConnection();
    String contentType = uc.getContentType();
    int contentLength = uc.getContentLength();
    if (contentType.startsWith("text/") || contentLength == -1) {
        throw new IOException("This is not a binary file.");
    }
    try (InputStream rwa = uc.getInputStream()) {
        InputStream in = new BufferedInputStream(rwa);
        byte[] data = new byte[contentLength];
        int offset = 0;
        while (offset < contentLength) {
            int bytesRead = in.read(data, offset, data.length - offset);
            if (bytesRead ==-1) break;
            offset += bytesRead;
        }
        if (offset != contentLength) {
            throw new IOException("not read all");
        }
        String filename = u.getFile();
        filename = filename.substring(filename.lastIndexOf("/") + 1);
        try (FileOutputStream fout = new FileOutputStream(filename)) {
            fout.write(data);
            fout.flush();
        }
    }
}

獲取內容編碼方式(位元組如何編碼成位元組)(不同於字元編碼):

public String getContentEncoding()

沒有編碼 返回null

獲取傳送時間:

public long getDate();//沒有就返回0
Date document = new Date(uc.getDate());

過期日期:

public long getExpiration()

最後修改日期:

public long getLastModified

獲取任意首部欄位

public String getHeaderField(String name);//不區分大小寫
public String getHeaderFieldKey(int n);//返回第n個首部欄位
public String getHeaderField(int n);//返回第n個欄位的值
public long getHeaderFieldDate(String name, long default);//將值轉換為long
public long getHeaderFieldInt(String name, int default);//轉化為int

快取

一般情況下使用get通過HTTP訪問的頁面可以快取,也應當快取,相關的HTTP首部:

Expires首部:指定快取的時間
Cache-control首部(和上面同出現,會覆蓋它):
    max-aget=[seconds]:
    s-maxage=[seconds]: 到過期之前的秒數
    public:可以快取一個經過認證的響應
    private: 僅單個使用者快取可以儲存響應
    no-cache: 客戶端每次都要用Etag或Last-modified首部重新驗證響應的狀態
    no-store:不管怎麼樣都不快取
Last_modified:最後一次修改的日期
Etag:驗證本地快取的標誌,標誌不同時,才執行get請求

java的web快取

預設情況下java並不完成快取,如果要快取需要:

ResponseCache(處理後面兩個的類),CacheRequest,CacheResponse

一旦安裝了快取,只要系統嘗試載入一個URL,它首先會在這個快取中找。
ResponseCache的兩個方法:

public abstract CacheResponse get(...);//獲取快取資料和首部(其中會用到CacheRequest)
public abstract CacheRequest put(...);//獲取快取,通過一個流

java要求一次只能有一個URL快取。要安裝或者改變快取,需要使用:

public static ResponseCace.setDefault()
public static void setDefault(ResponseCache responseCache)

配置連線:

URLConnection主要有7個保護的例項欄位,定了傳送的請求

URL url;
boolean DoInput = true;
boolean doOutput = false;
allowUserInteraction = defaultAllowUserInteraction;
boolean useCaches = defaultUserCaches;
long ifModifiedSince = 0;
boolean connected = false;

這些值都是通過get和set方法獲取和改變(後兩個沒有get和set,更改在連線之前)

配置請求的首部

URLConnection會有一些預設的首部,新增首部:

public void setRequestProperty(String name, String value);

增加屬性:

public void addRequestProperty(String name, String value);

獲取屬性:

public String getRequestProperty(String name);
public Map<String,List<String>> getRequestProperties();

向伺服器寫資料

URLConnection預設不輸出,因此請求輸出之前必須呼叫setDoOutput(true),這時請求方法變成POST。GET僅限於安全的操作,如搜尋請求或頁面導航,不能用於建立或修改資源的不安全操作。輸出通過流輸出:

public OutputStream getOutputStream();

案例:提交表單資料
編碼轉換的類:

public class QueryString {
    private StringBuilder query = new StringBuilder();

   public QueryString() {
   }
   public synchronized void add(String name, String value) {
       query.append("&");
       encode(name, value);
   }
   private void encode(String name, String value) {
       try {
           query.append(URLEncoder.encode(name, "UTF-8"));
           query.append("=");
           query.append(URLEncoder.encode(value, "UTF-8"));
       } catch (UnsupportedEncodingException e) {
           e.printStackTrace();
       }
   }
   public synchronized String getQuery() {
       return query.toString();
   }
   @Override
   public String toString() {
       return getQuery();
   }
}

主類:

public class FormPoster {
    private URL url;
    private QueryString query = new QueryString();

    public FormPoster(URL url) {
        if (!url.getProtocol().toLowerCase().startsWith("http")) {
            throw new IllegalArgumentException("not 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);
        try (OutputStreamWriter out = new OutputStreamWriter(uc.getOutputStream(),"UTF-8")) {
            out.write(query.toString());
            out.write("\r\n");
            out.flush();
        }
        return uc.getInputStream();
    }

    public static void main(String[] args) {
        URL url;
        if (args.length > 0) {
            try {
                url = new URL(args[0]);
            } catch (MalformedURLException e) {
                e.printStackTrace();
                return;
            }
        } else {
            try {
                url = new URL("http://www.xx.com/xx.html");
            } catch (MalformedURLException e) {
                e.printStackTrace();
                return;
            }
        }
        FormPoster poster = new FormPoster(url);
        poster.add("name", "xx");
        poster.add("email", "xx");
        try (InputStream in = poster.post()) {
            Reader r = new InputStreamReader(in);
            int c ;
            while ((c = r.read()) != -1) {
                System.out.println((char)c);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

URLConnection的安全性考慮

public Permission getPermission() throws IOException

返回一個Permission來測試是否能建立URLConnection連線

猜測MIME型別

僅是猜測

public static String guessContentTypeFromName(String name);
public static String guessContentTypeFromStream(InputStream in);

HttpURLConnection

該類是URLConnection的抽象子類。可以改變請求方法(預設是GET):

public void setRequestMethos(String method) throws ProtocolException

引數選項:GET POST HEAD PUT DELETE OPTIONS TRACE

獲取響應嗎和響應內容:

public int getResponseCode() throws IOException
public String getResponseMessage() throws IOException

得到錯誤訊息:

public InputStream getErrorStream()