全部產品
Search
文件中心

Alibaba Cloud DNS:Android端WebView情境下接入移動解析HTTPDNS Android SDK最佳實務方案

更新時間:Aug 15, 2025

本文為您提供Android端WebView情境下接入移動解析HTTPDNS Android SDK的最佳實務方案。

概述

Webview是Android系統提供的一個UI控制項,用來解析和顯示HTML+JS編寫的前端頁面。Android系統提供了API以實現WebView中的網路請求攔截與自訂邏輯注入。我們可以通過該API攔截WebView的各類網路請求,截取URL請求的Host,然後調用移動解析HTTPDNS Android SDK解析該Host,通過得到的IP組成新的URL來進行網路請求。本文旨在給出Android端在WebView的應用情境下接入移動解析HTTPDNSAndroid SDK的最佳實務供使用者參考。WebView在接入移動解析HTTPDNS Android SDK時,可應用於HTTP、HTTPS、SNI等情境,但需要滿足以下幾個前提條件:

  • Android SDK API Level > 21的裝置

  • HTTP請求報文頭不含Cookie的重新導向請求

  • Get請求

WebView情境下接入移動解析HTTPDNS Android SDK最佳實務完整代碼請參考Demo樣本工程源碼

實踐方案

public void setWebViewClient(WebViewClient client);

WebView提供了setWebViewClient介面對網路請求進行攔截,通過重載WebViewClient中的ShouldInterceptRequest方法,我們可以攔截到所有的網路請求:

public class WebViewClient{
       // API < 21
       public WebResourceResponse shouldInterceptRequest(WebView view,String url){
             .....
       } 
       // API >= 21
      public WebResourceResponse shouldInterceptRequest(WebView view,WebResourceRequest request) {
            .....
       }
     ......
 }
重要

Android SDK提供的shouldInterceptRequest方法在不同系統API下有不同版本。

  • 當API<21時,shouldInterceptRequest的版本為:

public WebResourceResponse shouldInterceptRequest(WebView view,String url)

此時僅能擷取到請求URL,要求方法、頭部資訊以及body等均無法擷取,強行攔截該請求可能無法得到正確響應。所以當API<21時,不對請求進行攔截:

public WebResourceResponse shouldInterceptRequest(WebView view,String url) {
      return super.shouldInterceptRequest(view, url);
}
  • 當API≥21時,shouldInterceptRequest提供的方法為:

public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
     String scheme = request.getUrl().getScheme().trim();
     String method = request.getMethod();
     Map<String, String> headerFields = request.getRequestHeaders();
     // 只能正常處理不帶body的請求
     if ((scheme.equalsIgnoreCase("http") || scheme.equalsIgnoreCase("https"))&& method.equalsIgnoreCase("get")) {
            ......
     } else {
           return super.shouldInterceptRequest(view, reqeust);
     }
}
重要

由於WebResourceRequest並沒有提供請求body資訊,所以只能攔截GET請求,不能攔截POST請求。

方案實現

  • 提供WebResourceResponse回調

webview攔截網路請求時,需要返回一個WebResourceResponse:

public WebResourceResponse(String mimeType, String encoding, InputStream data) ;

建立WebResourceResponse對象需要提供:請求的MIME類型、請求的編碼、請求的輸入資料流

其中請求的輸入資料流可以通過URLConnection.getInputStream()擷取,而MIME類型和encoding可以通過請求的ContentType擷取到,即通過URLConnection.getContentType ()獲得。

重要

並不是所有的請求都能得到完整的contentType資訊,此時可以參考如下策略。

String contentType = conn.getContentType();
String mime = getMime(contentType);
String charset = getCharset(contentType);

// 不含有MIME類型的請求不攔截
if (TextUtils.isEmpty(mime)) {
        return super.shouldInterceptRequest(view, request);
 } else {
       if (!TextUtils.isEmpty(charset)) {
             // 如果同時擷取到MIME和charset可以直接攔截
             return new WebResourceResponse(mime, charset, connection.getInputStream());
       } else {
             //擷取不到編碼資訊
             // 二進位資源無需編碼資訊,可以進行攔截
             if (isBinaryRes(mime)) {
                   Log.e(TAG, "binary resource for " + mime);
                   return new WebResourceResponse(mime, charset, connection.getInputStream());
            }else {
                   // 非二進位資源需要編碼資訊,不攔截
                  Log.e(TAG, "non binary resource for " + mime);
                 return super.shouldInterceptRequest(view, request);
           }
       }
  }

  • 佈建要求頭Host

public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
     ...... 
     URL url = new URL(request.getUrl().toString());
     conn = (HttpURLConnection) url.openConnection();
     //通過移動解析HTTPDNS Android SDK提供API獲得IP
     String ip = null;
     String[] ipv4Array = mDNSResolver.getIpv4ByHostFromCache(url.getHost(),true);
     if (ipv4Array != null && ipv4Array.length > 0) {
        ip = ipv4Array[0];
     }
     if (ip != null) {
           //Log.d(TAG, "get IP: " + ip + " for host: " + url.getHost() + "from pdns resolver success!");
          String newUrl = path.replaceFirst(url.getHost(), ip);
          conn = (HttpURLConnection) new URL(newUrl).openConnection(); 
          for (Map.Entry<String, String> field : headers.entrySet()) {
                //設定Http請求的Head頭部資訊
               conn.setRequestProperty(field.getKey(), field.getValue( ));
          }
      }
      // conn.setRequestProperty("Host", url.getHost());
    } 
}

情境案例

重新導向

通過攔截伺服器的Get請求,如果服務端的response包含重新導向,此時需要判斷原有請求中是否含有Cookie。如果原有要求標頭含Cookie,重新導向後Cookie會發生改變,這種情境下放棄攔截。如果原有要求標頭不包含Cookie,則需重新二次請求。

int code = conn.getResponseCode();
if (code >= 300 && code < 400) {
      if (請求前序中含有cookie) {
             // 不攔截
            return super.shouldInterceptRequest(view, request);
      }

      //臨時重新導向和永久重新導向location的大小寫有區分
      String location = conn.getHeaderField("Location");
      if (location == null) {
            location = conn.getHeaderField("location");
      }

      if (!(location.startsWith("http://") || location.startsWith("https://"))) {
             //補全url
             URL originalUrl = new URL(path);
             location = originalUrl.getProtocol() + "://"+ originalUrl.getHost() + location;
      }
      Log.e(TAG, "code:" + code + "; location:" + location + ";path" + path);
     發起二次請求
  } else {
        // redirect finish.
        Log.e(TAG, "redirect finish");
        ......
 }

HTTPS認證校正

如果攔截到的請求是HTTPS請求,此時還需要進行認證校正:

if (conn instanceof HttpsURLConnection) {
     final HttpsURLConnection httpsURLConnection = (HttpsURLConnection)conn;
     //https情境認證校正
     httpsURLConnection.setHostnameVerifier(new HostnameVerifier() {
         @Override
         public boolean verify(String hostname, SSLSession session) {
             String host = httpsURLConnection.getRequestProperty("Host");
             if (null == host) {
                   host = httpsURLConnection.getURL().getHost();
             }
             return HttpsURLConnection.getDefaultHostnameVerifier().verify(host, session);
       }
   });
}

HTTPS+SNI

如果HTTPS請求涉及到SNI情境,需要自訂SSLSocket,開發人員可以參考Android端HTTPS(含SNI)業務情境"IP直連"方案說明

重要
  1. 當前WebView接入移動解析HTTPDNS Android SDK最佳實務文檔只針對結合WebView情境下使用。

  2. 如何使用移動解析HTTPDNS Android SDK的網域名稱解析服務和接入移動解析HTTPDNS Android SDK的自身問題,請先查看Android SDK開發指南

  3. 開發人員在WebView開發人員在情境下接入移動解析HTTPDNS Android SDK最佳實務完整代碼請參考Demo樣本工程源碼。