Android筆記-網絡篇:HTTP & HTTPS

HTTP

基礎

超文本傳輸協議(HTTP,HyperText Transfer Protocol),默認端口:80html

特色

  1. 無鏈接:無鏈接的含義是限制每次鏈接只處理一個請求。服務器處理完客戶的請求,並收到客戶的應答後,即斷開鏈接。採用這種方式能夠節省傳輸時間。
  2. 無狀態:HTTP協議是無狀態協議,無狀態是指協議對於事務處理沒有記憶能力。缺乏狀態意味着若是後續處理須要前面的信息,則它必須重傳,這樣可能致使每次鏈接傳送的數據量增大。另外一方面,在服務器不須要先前信息時它的應答就較快。

請求報文

Http請求頭
  通常由請求行、請求頭、空行、請求體四部分組成。

響應報文

Http響應頭
  通常由狀態行、消息報頭、空行、響應正文四部分組成。

常見狀態碼

  • 200 OK:客戶端請求成功
  • 302 Move temporarily:請求的資源臨時從不一樣的 URI響應請求,重定向
  • 304 Not Modified:有效緩存
  • 400 Bad Request:客戶端請求有語法錯誤,不能被服務器所理解
  • 403 Forbidden:服務器收到請求,可是拒絕提供服務
  • 404 Not Found:請求失敗,請求所但願獲得的資源未被在服務器上發現
  • 500 Internal Server Error:服務器發生不可預期的錯誤
  • 503 Server Unavailable:服務器當前不能處理客戶端的請求,一段時間後可能恢復正常

常見通用報頭

  • Cache-Control:指定請求和響應遵循的緩存機制

經常使用請求報頭

  • Host:請求的主機名,容許多個域名同處一個IP地址,即虛擬主機
  • User-Agent:發送請求的瀏覽器類型、操做系統等信息
  • Accept:客戶端可識別的內容類型列表,用於指定客戶端接收那些類型的信息
  • Accept-Encoding:客戶端可識別的數據編碼
  • Connection:容許客戶端和服務器指定與請求/響應鏈接有關的選項,例如這是爲Keep-Alive則表示保持鏈接
  • Referer:容許客戶端指定請求uri的源資源地址,這能夠容許服務器生成回退鏈表,可用來登錄、優化cache等
  • Range:能夠請求實體的一個或者多個子範圍

常見響應報頭

  • Location:用於重定向接受者到一個新的位置,經常使用在更換域名的時候
  • Server:包含可服務器用來處理請求的系統信息,與User-Agent請求報頭是相對應的

常見實體報頭

  • Content-Type:發送給接收者的實體正文的媒體類型
  • Content-Lenght:實體正文的長度
  • Content-Encoding:實體報頭被用做媒體類型的修飾符,它的值指示了已經被應用到實體正文的附加內容的編碼,於是要得到Content-Type報頭域中所引用的媒體類型,必須採用相應的解碼機制
  • Last-Modified:實體報頭用於指示資源的最後修改日期和時間
  • Expires:實體報頭給出響應過時的日期和時間

SPDY

2012年google提出的SPDY方案,主要解決:java

  1. 下降延遲:SPDY採起了多路複用(multiplexing)。多路複用經過多個請求stream共享一個tcp鏈接的方式;
  2. 請求優先級:SPDY容許給每一個request設置優先級,這樣重要的請求就會優先獲得響應;
  3. header壓縮:選擇合適的壓縮算法能夠減少包的大小和數量;
  4. 基於HTTPS的加密協議傳輸
  5. 服務端推送

SPDY

Http2.0

  能夠當作是SPDY的升級版。android

Http2.0與SPDY的區別

  • HTTP2.0 支持明文 HTTP 傳輸,而 SPDY 強制使用 HTTPS
  • HTTP2.0 消息頭的壓縮算法採用 HPACK,而非 SPDY 採用的 DEFLATE

Http2.0新特性

  • 新的二進制格式:HTTP1.x的解析是基於文本的
  • 多路複用:即鏈接共享,即每個request都是是用做鏈接共享機制的
  • header壓縮
  • 服務端推送

HTTPS

(Hyper Text Transfer Protocol over Secure Socket Layer),是以安全爲目標的HTTP通道,即HTTP下加入SSL層,端口:443算法

HTTPS握手流程

Https流程
注意:下面流程與圖中序列不是一致的。

  1. 客戶端的瀏覽器向服務器傳送客戶端SSL協議的版本號,加密算法的種類,產生的隨機數,以及其餘服務器和客戶端之間通信所須要的各類信息;
  2. 服務器向客戶端傳送SSL協議的版本號,加密算法的種類,隨機數以及其餘相關信息,同時服務器還將向客戶端傳送本身的證書;
  3. 客戶利用服務器傳過來的信息驗證服務器的合法性,服務器的合法性包括:證書是否過時,發行服務器證書的CA是否可靠,發行者證書的公鑰可否正確解開服務器證書的「發行者的數字簽名」,服務器證書上的域名是否和服務器的實際域名相匹配。若是合法性驗證沒有經過,通信將斷開;若是合法性驗證經過,將繼續進行第四步;
  4. 用戶端隨機產生一個用於後面通信的「對稱密碼」,而後用服務器的公鑰(服務器的公鑰從步驟②中的服務器的證書中得到)對其加密,而後將加密後的「預主密碼」傳給服務器;
  5. 若是服務器要求客戶的身份認證(在握手過程當中爲可選),用戶能夠創建一個隨機數而後對其進行數據簽名,將這個含有簽名的隨機數和客戶本身的證書以及加密過的「預主密碼」一塊兒傳給服務器;
  6. 若是服務器要求客戶的身份認證,服務器必須檢驗客戶證書和簽名隨機數的合法性,具體的合法性驗證過程包括:客戶的證書使用日期是否有效,爲客戶提供證書的CA是否可靠,發行CA 的公鑰可否正確解開客戶證書的發行CA的數字簽名,檢查客戶的證書是否在證書廢止列表(CRL)中。檢驗若是沒有經過,通信馬上中斷;若是驗證經過,服務器將用本身的私鑰解開加密的「預主密碼」,而後執行一系列步驟來產生主通信密碼(客戶端也將經過一樣的方法產生相同的主通信密碼);
  7. 服務器和客戶端用相同的主密碼即「通話密碼」,一個對稱密鑰用於SSL協議的安全數據通信的加解密通信。同時在SSL通信過程當中還要完成數據通信的完整性,防止數據通信中的任何變化;
  8. 客戶端向服務器端發出信息,指明後面的數據通信將使用的步驟⑦中的主密碼爲對稱密鑰,同時通知服務器客戶端的握手過程結束;
  9. 服務器向客戶端發出信息,指明後面的數據通信將使用的步驟⑦中的主密碼爲對稱密鑰,同時通知客戶端服務器端的握手過程結束;
  10. SSL 的握手部分結束,SSL安全通道的數據通信開始,客戶和服務器開始使用相同的對稱密鑰進行數據通信,同時進行通信完整性的檢驗。

Android中處理Https

官方推薦:Android推薦方案瀏覽器

處理 javax.net.ssl.SSLHandshakeException: 證書驗證失敗

/**
     * HTTPS未知的證書頒發機構處理方法
     * Android客戶端存儲證書
     *
     * @param input 待信任的CA證書流
     * @return SSLContext
     */
    public static SSLContext getSSLContext(InputStream input) {
        try {
            SSLContext sslContext = SSLContext.getInstance("TLS");
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            Certificate ca = cf.generateCertificate(input);

            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            keyStore.load(null, null);
            keyStore.setCertificateEntry("ca", ca);

            TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            tmf.init(keyStore);

            sslContext.init(null, tmf.getTrustManagers(), null);
            input.close();
            return sslContext;
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (CertificateException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (KeyStoreException e) {
            e.printStackTrace();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        }

        return null;
    }
複製代碼

單獨使用SSL和HTTP

/**
     * 單獨使用SSL + HTTP時
     * @param trustManagers
     * @return
     */
    public static SSLContext getSSLContext(TrustManager[] trustManagers) {
        try {
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, trustManagers, null);
            return sslContext;
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static TrustManager[] sDefaultTrustManagers = new TrustManager[] {new X509TrustManager() {

        @Override
        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            // TODO: 2018/1/23雙向校驗中,向服務端發客戶端證書
        }

        @Override
        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            // TODO: 2018/1/23 雙向校驗中,校驗服務端證書
        }

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[0];
        }
    }};

    public static HostnameVerifier sHostnameVerifier = new HostnameVerifier() {
        @Override
        public boolean verify(String hostname, SSLSession session) {
            // 不驗證主機名
            return true;
        }
    };
複製代碼
相關文章
相關標籤/搜索