日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

URLConnection-URL连接

發布時間:2023/12/3 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 URLConnection-URL连接 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

【README】

  • 本文介紹了 URLConnection java類,通過 URLConnection 如何獲取網絡資源;
  • 本文還梳理了涉及網絡編程的java類的進化過程;從 URL -> URLConnection -> HttpURLConnection 或 HttpClient ;?
  • URL與URI的介紹, refer2?? java URL和URI_PacosonSWJTU的博客-CSDN博客

1. 按理URL 有獲取網絡資源的接口(如getContent(), getFile()),為啥還要封裝 URLConnection ? URL 獲取資源方法如下:

2. 很顯然, URL 只提供了客戶端與服務器簡單交互的功能,沒有提供復雜的交互功能,比如請求頭,緩存,字符編碼,鑒權,等等,并根據請求頭做出不同響應啊等等;所以引入 URLConnection來封裝客戶端與服務器間的復雜功能;

  • 2.1 URL 與 URLConnection 兩者間還有一個重要區別:
    • 2.1.1 URL 只能讀取網絡資源內容(單向),而 URLConnection 提供了不僅從服務器讀取數據,還有向服務器寫入數據的功能,是雙向交互;

3. 小結: URL 和 URLConnection的不同點

  • URLConnection 提供了對http的首部訪問接口;
  • URLConnection 可以配置發送給服務器的請求參數;
  • URLConnection除了可以讀取數據之外,還可以向服務器寫入數據; (數據流是雙向)

4.? 那為啥還要在 URLConnection的基礎上 引入 HttpURLConnection ?

abstract public class HttpURLConnection extends URLConnection {

?HttpURLConnection? 繼承了 URLConnection, 前者對后者的功能進行了擴展,以提供基于http協議的api,最顯著的差別是,提供了獲取錯誤輸入流,響應碼等方法,這是 URLConnection做不到的(根據下圖的方法列表,HttpURLConnection也只是一點點擴展);

5.? 我們再深入一下,既然有了 HttpURLConnection,那為啥 apache 還提供了 HttpClient-http客戶端工具包進行網絡編程?

在通常狀況下,若是只是須要向Web站點的某個簡單頁面提交請求并獲取服務器響應,HttpURLConnection徹底能夠勝任。
但訪問一些頁面需要復制操作如鑒權,這就涉及Session、Cookie的處理了,若是打算使用HttpURLConnection來處理這些細節,固然也是可能實現的,只是處理起來難度就大了
因此 為了簡化復雜的http網絡編程,apache提供了HttpClient工具包;

補充: 第5點并不是說不用 HttpURLConnection,全部用 HttpClient ;

要知道, 性能上 HttpURLConnection高于 HttpClient,簡單網絡請求用 HttpURLConnection更快,復雜請求如 保存會話session,cookie,使用緩存等 使用 HttpClient;可以理解為 HttpURLConnection 是 輕量級網絡請求, HttpClient 封裝了其他額外的功能,比較重量級

但是我們寫底層框架的時候,一般用的都是 HttpURLConnection,因為它是jdk自帶的,HttpClient 需要額外引入apache依賴,不便于后期框架代碼維護);


6. 下面給出 使用 URL, URLConnection, HttpURLConnection, HttpClient 讀取網絡資源的代碼示例

  • 6.1 根據 URL 獲取資源
// 根據 URL 獲取資源@Testpublic void f0 () throws Exception {URL url = new URL("http://www.baidu.com");try (InputStream inputStream = url.openStream()) {BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));String result = "";while((result = bufferedReader.readLine()) != null) {System.out.println(result);}}}
  • 6.2? 根據 URLConnection 獲取資源
// 根據 URLConnection 獲取資源@Testpublic void f1() throws Exception {URL u = new URL("http://www.baidu.com");// 打開連接獲取 URLConnection對象URLConnection uc = u.openConnection();uc.setAllowUserInteraction(true);// 讀取資源信息System.out.println("過期時間 " + uc.getExpiration());System.out.println("報文長度 " + uc.getContentLength());System.out.println("最后修改時間" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(uc.getLastModified())));// try資源塊-自動關閉輸入流try (InputStream inputStream = uc.getInputStream()) {BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));// 打印從服務器讀取的報文String line = "";while ((line = bufferedReader.readLine()) != null) {System.out.println(line);}}}
  • 6.3 根據 HttpURLConnection 獲取資源
// 根據 HttpURLConnection 獲取資源@Testpublic void f1_1() throws Exception {URL u = new URL("http://www.baidu.com");// 獲取 HttpURLConnection 連接HttpURLConnection httpUc = (HttpURLConnection) u.openConnection();// try資源塊-自動關閉輸入流try (InputStream inputStream = httpUc.getInputStream()) {BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));// 打印從服務器讀取的報文String line = "";while ((line = bufferedReader.readLine()) != null) {System.out.println(line);}}}
  • 6.4 根據 apache HttpClient 獲取資源
// 根據 apache HttpClient 獲取資源@Testpublic void f1_2() {//1.獲得一個httpclient對象CloseableHttpClient httpclient = HttpClients.createDefault();//2.生成一個get請求HttpGet httpget = new HttpGet("http://www.baidu.com");//3.執行get請求并返回結果try (CloseableHttpResponse response = httpclient.execute(httpget)) {// 判斷響應碼if (HttpStatus.SC_OK == response.getStatusLine().getStatusCode()) {// 讀取報文BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), StandardCharsets.UTF_8));String line = "";while((line = bufferedReader.readLine()) != null) {System.out.println(line);}}} catch (Exception e) {throw new RuntimeException("請求錯誤");}}

?【1】URLConnection 簡要介紹

1)URLConnection 是java的協議處理器機制的一部分,這個機制還包括 URLStatementHandler 類;

【1.1】打開 URLConnection

1)打開 URLConnection 與服務器交互步驟

  • 構造 URL 對象;
  • 調用 URL.openConnection() 獲取 URLConnection 對象;
  • 配置這個 URLConnection對象;
  • 讀取首部字段;(或有)
  • 獲取輸入流并讀取數據? 調用 URLConnection.getInputStream() ; (或有)
  • 獲取輸出流并寫入數據; (或有)
  • 關閉連接;?
  • // 打開 URLConnection 與服務器交互@Testpublic void f1() throws Exception {URL u = new URL("http://www.baidu.com");// 打開連接獲取 URLConnection對象URLConnection uc = u.openConnection();uc.setAllowUserInteraction(true);try (InputStream inputStream = uc.getInputStream()) { // try資源塊-自動關閉輸入流BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));// 打印從服務器讀取的報文String line = "";while((line = bufferedReader.readLine()) != null) {System.out.println(line);}}}

    【1.2】URLConnection 讀取首部(請求頭或響應頭)

    1)http首部包括 所請求網絡資源的內容類型,長度,內容編碼字符集,日期時間,內容過期時間,內容最后修改時間;

    【1.2.0】常用首部包括:

  • Content-type; 內容類型; MIME 內容類型; URLConnection.getContentType()
  • Content-length;內容字節長度; URLConnection.getContentLength()
  • Content-encoding,內容編碼(非字符編碼,字符編碼格式在 content-type中的mime類型指定); URLConnection.getContentEncoding()
  • Date, 內容產生時間; URLConnection.getDate()
  • Last-modified, 最后修改時間, 以便于緩存; URLConnection.getLastModified()
  • Expires, 到期時間, 以便于緩存;? URLConnection.getExpiration()
  • 【1.2.1】 getContentType 返回響應主體的 MIME內容類型 (多用途互聯網郵件擴展類型)

    1)常用的 mime類型包括

    • text/html
    • text/plain
    • image/gif
    • application/xml
    • image/jpeg
    • application/json

    2)如果內容類型是某種類型文本,那這個首部可能還包含一個字符集部分來標識文檔的字符編碼格式,如:

    Content-type: text/html; charset=UTF-8 或? Content-type: application/json; charset=UTF-8

    【1.2.2】getContentLength 獲取響應報文體字節個數

    • 1)getContentLength 返回是 int 類型,最多標識 2gb(2^31=2g=20億字節);
    • 2)隨著網絡發展,實際上很有可能資源大小超過 2gb; 在這種情況下 getContentLength 返回-1;

    java7 新增了 getContentLengthLong 方法 返回類型是long, 2^63 個字節,理論上可以接收 8000PB=800萬TB 個字節,足夠使用了;

    【1.2.3】getContentEncoding() 獲取內容編碼格式

    web上常用的內容編碼格式 可能是 x-gzip? 或? GZipInputStream 直接解碼;

    【1.2.4】getDate()? 指出文檔發送給客戶端的時間;

    【1.2.5】getExpiration()? 文檔在服務器的過期時間

    • 1)提示客戶端應該何時從緩存中刪除文檔,并從服務器重新下載;
    • 2)如果http首部沒有 expiration字段,getExpiration() 返回0, 表示文檔不會過期,將永遠保留在緩存中;

    【1.2.6】getLastModified 返回文檔的最后修改時間

    例子1, 讀取http常用響應頭

    // 讀取http常用響應頭@Testpublic void f0() throws Exception {// 格式化器SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");// 讀取 URLConnection 的常用響應頭URL url = new URL("http://www.baidu.com");URLConnection urlConnection = url.openConnection();// 讀取資源內容類型, mime 類型System.out.println("內容類型 = " + urlConnection.getContentType());// 讀取資源內容長度System.out.println("內容長度 = " + urlConnection.getContentLength());// 讀取資源內容編碼(如gzip,不是字符編碼,字符編碼在 content-type中的mime類型指定)System.out.println("內容編碼 = " + urlConnection.getContentEncoding());// 讀取指出文檔發送給客戶端的時間System.out.println("指出文檔發送給客戶端的時間 = " + simpleDateFormat.format(urlConnection.getDate()));// 讀取文檔在服務器的過期時間System.out.println("文檔在服務器的過期時間 = " + simpleDateFormat.format(urlConnection.getExpiration()));// 讀取 文檔的最后修改時間System.out.println("文檔的最后修改時間 = " + simpleDateFormat.format(urlConnection.getLastModified ()));}

    結果:

    內容類型 = text/html
    內容長度 = 2381
    內容編碼 = null
    指出文檔發送給客戶端的時間 = 2021-11-06 12:02:00
    文檔在服務器的過期時間 = 1970-01-01 08:00:00
    文檔的最后修改時間? = 1970-01-01 08:00:00

    例子2,讀取二進制資源文件,如圖片(百度上隨便搜索一張),mime類型為 image/jpeg ;

    @Testpublic void f1() throws Exception {URL url = new URL("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fbpic.588ku.com%2Felement_origin_min_pic%2F18%2F08%2F24%2F05dbcc82c8d3bd356e57436be0922357.jpg&refer=http%3A%2F%2Fbpic.588ku.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1638764377&t=703444b029255bfa2ddba73484dd7c7c");// 打開連接,判斷是否為圖片格式URLConnection urlConnection = url.openConnection();String contentType = urlConnection.getContentType(); // long contentLength = urlConnection.getContentLengthLong();int contentLength = urlConnection.getContentLength();System.out.println("文件內容類型=" + contentType + ", 內容長度=" + contentLength);if (!contentType.startsWith("image") || contentLength < 1) {throw new IOException("不是一個圖片文件");}// 讀取資源try (BufferedInputStream bufferedInputStream = new BufferedInputStream(url.openStream())) {byte[] data = new byte[contentLength];int offset = 0;int byteread = 0;while(offset < contentLength) {if ((byteread = bufferedInputStream.read(data, offset, data.length - offset)) == -1) {break;}offset += byteread;}if (offset != contentLength) {throw new IOException(MessageFormat.format("讀取失敗, 讀了{0}個字節,期望讀取{1}個字節", offset, contentLength));}// 寫入文件,獲取文件名String filename = url.getFile();System.out.println("資源文件名 = " + filename);filename = "temp01." + contentType.split("[\\W+]")[1];// 非詞字符正則分割try (FileOutputStream fos = new FileOutputStream("D:/temp/" + filename)) {fos.write(data);fos.flush();}}}

    結果:

    文件內容類型=image/jpeg, 內容長度=46417


    【1.3】獲取任意首部

    // 獲取任意首部@Testpublic void f1() throws Exception {URL url = new URL("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fbpic.588ku.com%2Felement_origin_min_pic%2F18%2F08%2F24%2F05dbcc82c8d3bd356e57436be0922357.jpg&refer=http%3A%2F%2Fbpic.588ku.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1638764377&t=703444b029255bfa2ddba73484dd7c7c");URLConnection urlConnection = url.openConnection();// 獲取所有首部(響應頭)的鍵值對Map<String, List<String>> headerFileds = urlConnection.getHeaderFields();Set<Map.Entry<String, List<String>>> entrySet = headerFileds.entrySet();entrySet.forEach(entry -> {String key = entry.getKey();System.out.println("key = " + key + ", 值列表=" + entry.getValue());}); // 獲取單個首部System.out.println("獲取單個首部");System.out.println("Content-Type = " + urlConnection.getHeaderField("Content-Type"));}

    結果:

    key = null, 值列表=[HTTP/1.1 200 OK]
    key = Server, 值列表=[JSP3/2.0.14]
    key = Access-Control-Allow-Origin, 值列表=[*]
    key = Ohc-Upstream-Trace, 值列表=[118.112.225.100]
    key = Connection, 值列表=[keep-alive]
    key = Last-Modified, 值列表=[Thu, 01 Jan 1970 00:00:00 GMT]
    key = Ohc-File-Size, 值列表=[46417]
    key = Date, 值列表=[Sat, 06 Nov 2021 04:42:29 GMT]
    key = Accept-Ranges, 值列表=[bytes]
    key = Ohc-Cache-HIT, 值列表=[cd6ct100 [4], bdix100 [4]]
    key = Ohc-Response-Time, 值列表=[1 0 0 0 0 0]
    key = ETag, 值列表=[927f0861741bd2135df3cbac979cdded]
    key = Timing-Allow-Origin, 值列表=[*]
    key = Expires, 值列表=[Sat, 04 Dec 2021 06:42:40 GMT]
    key = Content-Length, 值列表=[46417]
    key = Age, 值列表=[1287]
    key = Content-Type, 值列表=[image/jpeg]
    獲取單個首部
    Content-Type = image/jpeg


    【2】 緩存

    【2.1】緩存涉及的 http報文頭

    1)Expires 報文頭指示這個資源可以緩存,期限是指定的時間為止;

    2)Cache-control 首部提供了更加細粒度的緩存策略;

    Cache-control 會覆蓋 Expires ,即優先級 前者高于后者;服務器可以在一個首部中發送多個 Cache-control 首部,只要它們沒有沖突;?

    3)Last-modified 指示資源最后一次修改日期。只有當本地緩存的副本早于這個日期,才會到服務器獲取資源,否則客戶端一直使用本地緩存;

    4)Etag首部: 資源改變時的唯一標識; 當客戶端資源副本的Etag 與 服務器不同時,才會到服務器獲取資源,否則客戶端一直使用本地緩存;

    5)緩存策略(干貨):

  • 如果本地緩存中有這個資源的一個表示, 而且還沒有到它的過期時間 Expires,那么可以直接使用這個資源,而無需請求服務器;
  • 如果本地緩存中有這個資源的一個表示,但到了過期時間,在完成 get請求前,可以檢查服務器首部的head首部 Etag,查看資源是否已經改變;
  • 6)java自帶的web緩存類

    默認情況下,java并沒有緩存。需要安裝URL類使用的系統級緩存,需要有:

    • ResponseCache的子類;
    • CacheRequest的子類;
    • CacheResponse的子類;

    【3】配置 URLConnection連接

    【3.1】配置屬性及其方法

    1)URLConnection定義了7個保護字段,定義了客戶端如何向服務器發送請求;

    • 1.1)protected URL url, 指定這個 URLConnection 連接 URL;初始化一次,不能修改;
    • 1.2)protected boolean connected,是否連接;連接打開,該值為true,連接關閉,該值為false;connect(), getInputStream(), getOutputStream() 都會打開連接; disconnect() 關閉連接;?
    • 1.3)protected boolean allowUserInteraction, 指示了是否允許用戶交互;只能在打開連接前設置,連接后設置拋出異常;
    • 1.4)protected boolean doInput,是否可以從服務器服務器讀取資源;補充 URConnection 可以用于讀取服務器,寫入服務器,或讀寫服務器;但響應字段要設置為true;
    • 1.5)protected boolean doOutput,是否可以向服務器寫入數據; 當為一個 http URL的doOutput設置為 true時,請求方法從 GET 修改為 POST
    • 1.6)protected boolean ifModifiedSince,設置為true,則客戶端請求報文頭包括一個首部 If-Modified-Since,值日期時間格式;如果服務器文檔在這個時間之后修改,則發送該文檔,否則不發送(而發送響應碼 304 Not Modified),客戶端使用本地緩存;? URLConnection的 ifModifiedSince 字段指定了 放置在 If-Modified-Since 首部字段中的日期,調用 setIfModifiedSince(long ifModifiedSince毫秒數) 來設置;
    • 1.7)protected boolean useCaches, 客戶端是否使用本地緩存; URCConnection.setUseCahces(false) 用于禁用本地緩存;?

    2)URLConnection 連接屬性設置例子

    // URCConnection 連接屬性設置例子@Testpublic void f3() throws Exception {URL u = new URL("http://www.baidu.com");// 打開連接獲取 URLConnection對象URLConnection uc = u.openConnection();uc.setAllowUserInteraction(true); // 允許交互uc.setDoInput(true); // 可以從服務器讀取數據uc.setDoOutput(true); // 可以向服務器寫入數據uc.setIfModifiedSince(new Date().getTime()); // 設置資源最后修改時間uc.setUseCaches(false); // 禁用緩存// try資源塊-自動關閉輸入流try (InputStream inputStream = uc.getInputStream()) {BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));// 打印從服務器讀取的報文String line = "";while ((line = bufferedReader.readLine()) != null) {System.out.println(line);}}}

    【3.2】超時

    • setConnectionTimeout(int),設置連接獲取超時時間;
    • setReadTimeout(int) ,設置讀取服務器資源超時時間;?

    【4】配置客戶端請求http首部

    【4.1】增加首部字段

    1) URLConnection.setRequestProperty(String name, String value) 為http首部增加字段;

    其允許一個name,有多個value,多個value通過逗號隔開; 該方法只能在 打開連接前使用;

    【4.2】向服務器寫入數據

    // 向服務器寫入數據@Testpublic void f4() throws Exception {URL u = new URL("http://www.baidu.com");// 打開連接,把請求方法從get變為postURLConnection uc = u.openConnection();uc.setDoOutput(true); // get 變為 postuc.setRequestProperty("cookie", "username=zhangsan; password=123456; session=B2C7E8A1F2F5E8"); // 設置cookie請求頭 // 寫入數據到servertry(OutputStream outputStream = uc.getOutputStream()) {outputStream.write("四川省成都市高新區".getBytes(StandardCharsets.UTF_8));}System.out.println("寫入數據成功,bingo");}

    【5】HttpURLConnection

    HttpURLConnection 是抽象類,構造函數是保護類型,所以不能直接創建;

    URL.openConnection() 返回的就是一個 HttpURLConnection的一個實例; 如下:

    URL u = new URL("http://www.baidu.com"); // 獲取 HttpURLConnection 連接 HttpURLConnection httpUc = (HttpURLConnection) u.openConnection();

    【5.1】 請求方法

    1)改變請求方法

    HttpURLConnection.setRequestMethod() 用于修改請求方法;

    2)請求方法包括:

    • GET,請求資源,但沒有請求體;
    • POST,請求資源, 有請求體;
    • HEAD,告訴服務器只返回http首部,不用實際發送文件 ;常見用途是檢查文件的最后修改時間;
    • PUT,html編輯器或向上傳文件到服務器使用put方法;
    • DELETE,刪除web服務器上的文件;
    • OPTIONS,詢問某個url 支持哪些選項;
    • TRACE ,trace會發送http報文頭,服務器接收這個報文頭;可以查看 服務器和客戶端之間的代理服務器做了哪些修改;

    3)restful api中 方法類型與業務操作對應關系

    序號方法類型業務操作
    1get查詢數據
    2post新增數據
    3put修改或更新數據
    4delete刪除數據

    【5.2】斷開與服務器的連接

    調用 HttpURLConnection.disconnect() 方法可以關閉連接,同時關閉流;但關閉流不會關閉連接;

    【5.3】處理服務器響應

    1)響應報文示例

    ?

    注意: 響應報文頭 與 響應實體間 有一個空行(作為分隔符),圖片中我忘記標識出來了,特此說明

    ?2)獲取響應碼和響應報文

    // 獲取響應碼和響應報文@Testpublic void f6() throws Exception {URL u = new URL("http://www.baidu.com");// 打開連接,把請求方法從get變為postHttpURLConnection httpURLConnection = (HttpURLConnection) u.openConnection();System.out.println("響應碼 = " + httpURLConnection.getResponseCode());System.out.println("響應消息 = " + httpURLConnection.getResponseMessage());// 獲取所有響應頭for (int i = 1; ; i++) {String header = httpURLConnection.getHeaderField(i);String key = httpURLConnection.getHeaderFieldKey(i);if (header == null || key == null) break;System.out.println("key=" + key + ", value=" + header);}}

    打印結果:

    響應碼? = 200
    響應消息? = OK
    key=Content-Length, value=2381
    key=Content-Type, value=text/html
    key=Server, value=bfe
    key=Date, value=Sat, 06 Nov 2021 08:51:40 GMT

    3)補充:HttpURLConnection 封裝了很多常量響應碼

    總結

    以上是生活随笔為你收集整理的URLConnection-URL连接的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。