亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java Http多次請求復(fù)用同一連接示例詳解

 更新時間:2022年10月31日 11:53:56   作者:顏如玉  
這篇文章主要為大家介紹了Java Http多次請求復(fù)用同一連接示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

概述

注:

  • 本文乃是最簡單的實(shí)現(xiàn),真實(shí)場景要復(fù)雜麻煩的多
  • 旨在闡述清晰多次HTTP請求復(fù)用一個連接的底層邏輯

早在HTTP/1.0時代,每次HTTP請求都要創(chuàng)建一個連接,而創(chuàng)建連接的過程需要消耗資源和時間,代價相對昂貴,為了減少資源消耗,縮短響應(yīng)時間,就需要重用連接。在后來的HTTP/1.1中,引入了連接復(fù)用的機(jī)制,Http Header中加入Connection: keep-alive來告訴對方這個請求響應(yīng)完成后先不忙關(guān)閉,這也是本篇文章的由來。

復(fù)用的基本條件

理論基礎(chǔ)

OSI是Open System Interconnection的縮寫,意為開放式系統(tǒng)互聯(lián)。國際標(biāo)準(zhǔn)化組織(ISO)制定了OSI模型,該模型定義了不同計算機(jī)互聯(lián)的標(biāo)準(zhǔn),是設(shè)計和描述計算機(jī)網(wǎng)絡(luò)通信的基本框架。也就是如下七層模型:

當(dāng)然也有大家熟知的五層模型,也就是把會話層、表示層、應(yīng)用層合稱為應(yīng)用層。耳熟能詳?shù)腡CP、UDP屬于數(shù)量稀少的傳輸層協(xié)議。在這之上的應(yīng)用層協(xié)議百花齊放諸如:HTTP、SMTR、FTP......,然后很多中間件也自定義了通訊協(xié)議,比如Dubbo、Mysql。

讀到這里大家可能就已經(jīng)清醒的意識到,即使同屬應(yīng)用層的協(xié)議,是否支持長連接也不盡相同。筆者想要傳達(dá)的一個認(rèn)知:之所以能支持長連接,那是因?yàn)門CP經(jīng)歷三次握手建立連接之后,如果不出現(xiàn)其他意外是可以保證連接狀態(tài)的。也就是說應(yīng)用層協(xié)議是否屬于長連接僅僅取決于成功建立TCP,發(fā)送一個請求之后,對該連接的處理策略:

  • 如早期的HTTP每次發(fā)送請求,Server端回復(fù)完畢之后直接關(guān)閉則是短連接
  • 如Mysql處理完一條SQL請求,然后繼續(xù)執(zhí)行下一個則是長連接

這其實(shí)就是我們的理論基礎(chǔ),HTTP有希望支持長連接的前提是TCP本身就是長連接。

現(xiàn)實(shí)基礎(chǔ)

HTTP協(xié)議并非魔法,不是說新增一條規(guī)范,也不是簡簡單單的Header中加入Connection: keep-alive就能立馬支持長連接了。想要達(dá)到這個目的需要Client、Server端共同努力。

客戶端譬如Chrome瀏覽器,服務(wù)端譬如阿里OSS,像這樣兩端都支持了新的規(guī)范,HTTP才能快樂的成為長連接陣營中的一員。

獲取HTTP資源常見方式

因?yàn)镴DK提供了相關(guān)工具、且平臺相關(guān)的第三方包也足夠優(yōu)秀,所以Java獲取HTTP資源并非難事。

@Slf4j
public class SinaPicDownload {
    /* 微博上某個畫師的作品 */
    static final String HTTP_URL = "https://wx3.sinaimg.cn/mw2000/006jQ3i8ly1h5k50zujydj35k0334kjo.jpg";
    /* 下載之后放在顏如玉電腦的io文件下 */
    static final String LOCAL = "/Users/admin/io/靈魂蓮華-皎月.jpeg";
    public static void main(String[] args) {
        try (
            InputStream in = new URL(HTTP_URL).openStream();
            FileOutputStream out = new FileOutputStream(LOCAL)
        ) {
            byte[] buffer = new byte[1024 << 2];
            int read;
            while ((read = in.read(buffer)) > -1) {
                out.write(buffer, 0, read);
            }
            out.flush();
        } 
        catch (Throwable e) {
            log.error("獲取HTTP資源失敗:", e);
        }
    }
}

配合Java 7之后提供的try-with-resources語法糖,你甚至僅僅只需要不到二十行的代碼就可以輕而易舉的達(dá)到目的,但是缺點(diǎn)也顯而易見,通過這種方法每次只能獲取一個資源,用完之后只能完畢。我當(dāng)時就在想,Java怎么實(shí)現(xiàn)一次連接多次請求呢?

Transfer-Encoding

筆者在上文提到的理論基礎(chǔ)上推測到肯定可以使用Java提供的Socket建立TCP連接,關(guān)鍵問題是怎么跟Server端描述HTTP請求呢?

類比到現(xiàn)實(shí)生活中,兩者能順暢交流必然要求雙方都可以聽懂對方的語言。那HTTP有沒有一種Client、Server都能解析的規(guī)范呢,HTTP Transfer-Encoding正是在這種背景下應(yīng)運(yùn)而生。通俗的來講Transfer-Encoding就是一種雙方都約定好的格式,我按照這個格式Encoding,你按照這個格式Decoding,ta大概長這個樣子:

可想而知剛剛獲取那張圖片資源的是時候,我們肯定是這么跟新浪微博服務(wù)端說的:

聲明:

  • 真實(shí)的Request Line與圖中一致
  • Header其實(shí)復(fù)雜很多,配圖做了簡化
  • 該請求Body為空,圖中略過

簡略實(shí)現(xiàn)

先聲明一些常量,以備后用

@Slf4j
public class ReusableHttp {
    /* 顏如玉公司的OSS服務(wù)域名 */
    static final String HOST = "****.oss-cn-zhangjiakou.aliyuncs.com";
    static final int PORT = 80;
    /* 顏如玉在OSS上放置的幾個資源 */
    static final String[] URLS = new String[]{
        "/context/reusable/gtyj.text",
        "/context/reusable/tlyxqch.text",
        "/context/reusable/yj.text",
        "/context/reusable/ls.text"
    };
    /* CR = '\r'; LF = '\n'*/
    static final byte[] CRLF = new byte[]{Chars.CR, Chars.LF};
    static final String LOCAL_PATH = "/Users/admin/io/";
}

建立TCP連接,然后獲得輸出,輸入流

public static void main(String[] args) {
    try {
        try (
            Socket socket = new Socket(HOST, PORT);
            OutputStream out = socket.getOutputStream();
            InputStream in = socket.getInputStream()
        ) {
            /* 復(fù)用連接,獲取資源 */
            reusable(out, in);
        }
    }
    catch (IOException e) {
        log.error("請求出現(xiàn)異常", e);
    }
}

寫出Request Line

/**
 * Write Request Line
 *
 * RequestLine encoding規(guī)范
 *
 * **********************************************
 * * method * sp * URL * sp * version * cr * lf *
 * **********************************************
 */
static void writeRequestLine(OutputStream out, String url) throws IOException {
    /* 注意空格一定要按照規(guī)定來擺放 */
    out.write(("GET " + url + " HTTP/1.1").getBytes());
    /* 最后再寫入一個回車、換行符表示Request Line結(jié)束 */
    out.write(CRLF);
}

寫出Request Header

/**
 * Write Request Header
 *
 * HeaderLine encoding規(guī)范
 *
 * *******************************************
 * * header field name * : * value * cr * lf *
 * *******************************************
 * ....
 * *******************************************
 * * header field name * : * value * cr * lf *
 * *******************************************
 * ...
 * ***********
 * * cr * lf *
 * ***********
 * ***************
 * * Entity Body *
 * ***************
 */
static void writeHeaderLine(OutputStream out) throws IOException {
    out.write("Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9".getBytes());
    out.write(CRLF);
    out.write("Accept-Encoding: gzip, deflate".getBytes());
    out.write(CRLF);
    out.write("Accept-Language: zh-CN,zh;q=0.9".getBytes());
    out.write(CRLF);
    out.write("Connection: keep-alive".getBytes());
    out.write(CRLF);
    out.write("Host: kuaimai-sheji.oss-cn-zhangjiakou.aliyuncs.com".getBytes());
    out.write(CRLF);
    /* 最后再寫入一個回車、換行符表示Request Header結(jié)束 */
    out.write(CRLF);
}

因?yàn)槭呛唵蔚恼埱?,所以直接省略Request Body。發(fā)出如上報文后,Server端會解析請求,然后回復(fù)。

/**
 * 1.向Server端寫出請求
 * 2.接受Server端回復(fù)
 * 3.寫到顏如玉本地機(jī)器的io文件夾下
 *
 * @param out 往Server端寫出流
 * @param in  Server端往Client端寫入流
 */
static void reusable(OutputStream out, InputStream in) throws IOException {
    for (int i = 0, s = URLS.length; i < s; i++) {
        writeRequestLine(out, URLS[i]);
        writeHeaderLine(out);
        out.flush();
        byte[] bytes = new byte[512];
        in.read(bytes);
        String file = LOCAL_PATH + i + ".text";
        try (
            FileOutputStream fo = new FileOutputStream(file)
        ) {
            fo.write(bytes);
            fo.flush();
        }
        catch (Throwable e) {
            log.error("文件寫入出現(xiàn)異常", e);
        }
    }
}

可以看到功能已經(jīng)實(shí)現(xiàn),同一連接我反復(fù)請求了四次,最終得到四個資源。

以上就是Java Http多次請求復(fù)用同一連接示例詳解的詳細(xì)內(nèi)容,更多關(guān)于Java Http多請求復(fù)用的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 一篇文章帶你深入了解Java類加載

    一篇文章帶你深入了解Java類加載

    這篇文章主要介紹了Java中類加載過程全面解析,具有一定參考價值,需要的朋友可以了解下,希望能給你帶來幫助
    2021-08-08
  • spring-cloud入門之eureka-server(服務(wù)發(fā)現(xiàn))

    spring-cloud入門之eureka-server(服務(wù)發(fā)現(xiàn))

    本篇文章主要介紹了spring-cloud入門之eureka-server(服務(wù)發(fā)現(xiàn)),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-01-01
  • MyBatis通用Mapper中的通用example(排序)詳解

    MyBatis通用Mapper中的通用example(排序)詳解

    這篇文章主要介紹了MyBatis通用Mapper中的通用example(排序)詳解,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • Java通過MySQL的加解密函數(shù)實(shí)現(xiàn)敏感字段存儲

    Java通過MySQL的加解密函數(shù)實(shí)現(xiàn)敏感字段存儲

    這篇文章主要介紹了如何在Java中MySQL的加解密函數(shù)實(shí)現(xiàn)敏感字段存儲,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2022-03-03
  • mybatis-plus getOne和邏輯刪除問題詳解

    mybatis-plus getOne和邏輯刪除問題詳解

    這篇文章主要介紹了mybatis-plus getOne和邏輯刪除,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-08-08
  • Java中的六種經(jīng)典比較排序算法

    Java中的六種經(jīng)典比較排序算法

    排序算法是程序開發(fā)和計算機(jī)科學(xué)中常見的算法之一,排序算法是算法分析的重要內(nèi)容之一,因?yàn)榕判蛩惴ǖ男视绊懼绦虻男阅芎头€(wěn)定性,本文的目的是介紹常見的排序算法,并且通過代碼示例演示它們的實(shí)現(xiàn)過程,需要的朋友可以參考下
    2023-06-06
  • mybatis-plus 處理大數(shù)據(jù)插入太慢的解決

    mybatis-plus 處理大數(shù)據(jù)插入太慢的解決

    這篇文章主要介紹了mybatis-plus 處理大數(shù)據(jù)插入太慢的解決,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • SpringBoot JPA使用配置過程詳解

    SpringBoot JPA使用配置過程詳解

    這篇文章主要介紹了SpringBoot JPA使用配置過程詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-05-05
  • My eclipse 端口占用(9360)問題解決辦法

    My eclipse 端口占用(9360)問題解決辦法

    這篇文章主要介紹了My eclipse 工程發(fā)布時出現(xiàn)端口占用問題解決辦法的相關(guān)資料,需要的朋友可以參考下
    2016-12-12
  • Java實(shí)現(xiàn)插入公式到PPT的示例代碼

    Java實(shí)現(xiàn)插入公式到PPT的示例代碼

    PPT中可插入公式,用于放映時演示相關(guān)內(nèi)容的論證、推算的依據(jù)。通過代碼,我們可借助特定的工具來實(shí)現(xiàn)在PPT中的插入公式,本文將對此作詳細(xì)介紹
    2022-07-07

最新評論