中文字幕在线观看,亚洲а∨天堂久久精品9966,亚洲成a人片在线观看你懂的,亚洲av成人片无码网站,亚洲国产精品无码久久久五月天

使用單例模式實(shí)現(xiàn)的HttpClient工具類

2018-07-20    來(lái)源:open-open

容器云強(qiáng)勢(shì)上線!快速搭建集群,上萬(wàn)Linux鏡像隨意使用

引子

在Android開(kāi)發(fā)中我們經(jīng)常會(huì)用到網(wǎng)絡(luò)連接功能與服務(wù)器進(jìn)行數(shù)據(jù)的交互,為此Android的SDK提供了Apache的HttpClient來(lái)方便我們使用各種Http服務(wù)。你可以把HttpClient想象成一個(gè)瀏覽器,通過(guò)它的API我們可以很方便的發(fā)出GET,POST請(qǐng)求(當(dāng)然它的功能遠(yuǎn)不止這些)。

比如你只需以下幾行代碼就能發(fā)出一個(gè)簡(jiǎn)單的GET請(qǐng)求并打印響應(yīng)結(jié)果:

try {
        // 創(chuàng)建一個(gè)默認(rèn)的HttpClient
        HttpClient httpclient =new DefaultHttpClient();
        // 創(chuàng)建一個(gè)GET請(qǐng)求
        HttpGet request =new HttpGet("www.google.com");
        // 發(fā)送GET請(qǐng)求,并將響應(yīng)內(nèi)容轉(zhuǎn)換成字符串
        String response = httpclient.execute(request, new BasicResponseHandler());
        Log.v("response text", response);
    } catch (ClientProtocolException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }

為什么要使用單例HttpClient?

這只是一段演示代碼,實(shí)際的項(xiàng)目中的請(qǐng)求與響應(yīng)處理會(huì)復(fù)雜一些,并且還要考慮到代碼的容錯(cuò)性,但是這并不是本篇的重點(diǎn)。注意代碼的第三行:

HttpClient httpclient =new DefaultHttpClient();

在發(fā)出HTTP請(qǐng)求前,我們先創(chuàng)建了一個(gè)HttpClient對(duì)象。那么,在實(shí)際項(xiàng)目中,我們很可能在多處需要進(jìn)行HTTP通信,這時(shí)候我們不需要為每個(gè)請(qǐng)求都創(chuàng)建一個(gè)新的HttpClient。因?yàn)橹耙呀?jīng)提到,HttpClient就像一個(gè)小型的瀏覽器,對(duì)于整個(gè)應(yīng)用,我們只需要一個(gè)HttpClient就夠了。看到這里,一定有人心里想,這有什么難的,用單例啊!就像這樣:

publicclass CustomerHttpClient {
    privatestatic HttpClient customerHttpClient;
    
    private CustomerHttpClient() {
    }
    
    publicstatic HttpClient getHttpClient() {
        if(null== customerHttpClient) {
            customerHttpClient =new DefaultHttpClient();
        }
        return customerHttpClient;
    }
}

那么,哪里不對(duì)勁呢?或者說(shuō)做的還不夠完善呢?

多線程!試想,現(xiàn)在我們的應(yīng)用程序使用同一個(gè)HttpClient來(lái)管理所有的Http請(qǐng)求,一旦出現(xiàn)并發(fā)請(qǐng)求,那么一定會(huì)出現(xiàn)多線程的問(wèn)題。這就好像我們的瀏覽器只有一個(gè)標(biāo)簽頁(yè)卻有多個(gè)用戶,A要上google,B要上baidu,這時(shí)瀏覽器就會(huì)忙不過(guò)來(lái)了。幸運(yùn)的是,HttpClient提供了創(chuàng)建線程安全對(duì)象的API,幫助我們能很快地得到線程安全的“瀏覽器”。

public class CustomerHttpClient {
    private staticfinal String CHARSET = HTTP.UTF_8;
    private static HttpClient customerHttpClient;

    private CustomerHttpClient() {
    }

    public static synchronized HttpClient getHttpClient() {
        if (null== customerHttpClient) {
            HttpParams params =new BasicHttpParams();
            // 設(shè)置一些基本參數(shù)
            HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
            HttpProtocolParams.setContentCharset(params,
                    CHARSET);
            HttpProtocolParams.setUseExpectContinue(params, true);
            HttpProtocolParams
                    .setUserAgent(
                            params,
                            "Mozilla/5.0(Linux;U;Android 2.2.1;en-us;Nexus One Build.FRG83) "
                                    +"AppleWebKit/553.1(KHTML,like Gecko) Version/4.0 Mobile Safari/533.1");
            // 超時(shí)設(shè)置
/* 從連接池中取連接的超時(shí)時(shí)間 */
            ConnManagerParams.setTimeout(params, 1000);
            /* 連接超時(shí) */
            HttpConnectionParams.setConnectionTimeout(params, 2000);
            /* 請(qǐng)求超時(shí) */
            HttpConnectionParams.setSoTimeout(params, 4000);
            
            // 設(shè)置我們的HttpClient支持HTTP和HTTPS兩種模式
            SchemeRegistry schReg =new SchemeRegistry();
            schReg.register(new Scheme("http", PlainSocketFactory
                    .getSocketFactory(), 80));
            schReg.register(new Scheme("https", SSLSocketFactory
                    .getSocketFactory(), 443));

            // 使用線程安全的連接管理來(lái)創(chuàng)建HttpClient
            ClientConnectionManager conMgr =new ThreadSafeClientConnManager(
                    params, schReg);
            customerHttpClient =new DefaultHttpClient(conMgr, params);
        }
        return customerHttpClient;
    }
}

在上面的getHttpClient()方法中,我們?yōu)镠ttpClient配置了一些基本參數(shù)和超時(shí)設(shè)置,然后使用ThreadSafeClientConnManager來(lái)創(chuàng)建線程安全的HttpClient。上面的代碼提到了3種超時(shí)設(shè)置,比較容易搞混,故在此特作辨析。


HttpClient的3種超時(shí)說(shuō)明

/* 從連接池中取連接的超時(shí)時(shí)間 */
ConnManagerParams.setTimeout(params, 1000);
/* 連接超時(shí) */
HttpConnectionParams.setConnectionTimeout(params, 2000);
/* 請(qǐng)求超時(shí) */
HttpConnectionParams.setSoTimeout(params, 4000);

第一行設(shè)置ConnectionPoolTimeout:這定義了從ConnectionManager管理的連接池中取出連接的超時(shí)時(shí)間,此處設(shè)置為1秒。

第二行設(shè)置ConnectionTimeout: 這定義了通過(guò)網(wǎng)絡(luò)與服務(wù)器建立連接的超時(shí)時(shí)間。Httpclient包中通過(guò)一個(gè)異步線程去創(chuàng)建與服務(wù)器的socket連接,這就是該socket連接的超時(shí)時(shí)間,此處設(shè)置為2秒。

第三行設(shè)置SocketTimeout: 這定義了Socket讀數(shù)據(jù)的超時(shí)時(shí)間,即從服務(wù)器獲取響應(yīng)數(shù)據(jù)需要等待的時(shí)間,此處設(shè)置為4秒。

以上3種超時(shí)分別會(huì)拋出ConnectionPoolTimeoutException,ConnectionTimeoutException與SocketTimeoutException。

封裝簡(jiǎn)單的POST請(qǐng)求

有了單例的HttpClient對(duì)象,我們就可以把一些常用的發(fā)出GET和POST請(qǐng)求的代碼也封裝起來(lái),寫進(jìn)我們的工具類中了。目前我僅僅實(shí)現(xiàn)發(fā)出POST請(qǐng)求并返回響應(yīng)字符串的方法以供大家參考。將以下代碼加入我們的CustomerHttpClient類中:

privatestaticfinal String TAG ="CustomerHttpClient";

publicstatic String post(String url, NameValuePair... params) {
        try {
            // 編碼參數(shù)
            List<NameValuePair> formparams =new ArrayList<NameValuePair>(); // 請(qǐng)求參數(shù)
for (NameValuePair p : params) {
                formparams.add(p);
            }
            UrlEncodedFormEntity entity =new UrlEncodedFormEntity(formparams,
                    CHARSET);
            // 創(chuàng)建POST請(qǐng)求
            HttpPost request =new HttpPost(url);
            request.setEntity(entity);
            // 發(fā)送請(qǐng)求
            HttpClient client = getHttpClient();
            HttpResponse response = client.execute(request);
            if(response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
                thrownew RuntimeException("請(qǐng)求失敗");
            }
            HttpEntity resEntity =  response.getEntity();
            return (resEntity ==null) ?null : EntityUtils.toString(resEntity, CHARSET);
        } catch (UnsupportedEncodingException e) {
            Log.w(TAG, e.getMessage());
            returnnull;
        } catch (ClientProtocolException e) {
            Log.w(TAG, e.getMessage());
            returnnull;
        } catch (IOException e) {
            thrownew RuntimeException("連接失敗", e);
        }

    }


使用我們的CustomerHttpClient工具類

現(xiàn)在,在整個(gè)項(xiàng)目中我們都能很方便的使用該工具類來(lái)進(jìn)行網(wǎng)絡(luò)通信的業(yè)務(wù)代碼編寫了。下面的代碼演示了如何使用username和password注冊(cè)一個(gè)賬戶并得到新賬戶ID。

final String url ="http://yourdomain/context/adduser";
    //準(zhǔn)備數(shù)據(jù)
    NameValuePair param1 =new BasicNameValuePair("username", "張三");
    NameValuePair param2 =new BasicNameValuePair("password", "123456");
    int resultId =-1;
    try {
        // 使用工具類直接發(fā)出POST請(qǐng)求,服務(wù)器返回json數(shù)據(jù),比如"{userid:12}"
        String response = CustomerHttpClient.post(url, param1, param2);
        JSONObject root =new JSONObject(response);
        resultId = Integer.parseInt(root.getString("userid"));
        Log.i(TAG, "新用戶ID:"+ resultId);
    } catch (RuntimeException e) {
        // 請(qǐng)求失敗或者連接失敗
        Log.w(TAG, e.getMessage());
        Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT);
    } catch (Exception e) {
        // JSon解析出錯(cuò)
        Log.w(TAG, e.getMessage());
    }


結(jié)語(yǔ)

可以看到,使用工具類能大大提高在項(xiàng)目中編寫網(wǎng)絡(luò)通信代碼的效率。不過(guò)該工具類還有待完善,歡迎各位補(bǔ)充和矯正錯(cuò)誤,希望最后能完成一個(gè)工具類作為使用HttpClient的最佳實(shí)踐。(完)


標(biāo)簽: Google linux ssl 安全 代碼 服務(wù)器 通信 網(wǎng)絡(luò)

版權(quán)申明:本站文章部分自網(wǎng)絡(luò),如有侵權(quán),請(qǐng)聯(lián)系:west999com@outlook.com
特別注意:本站所有轉(zhuǎn)載文章言論不代表本站觀點(diǎn)!
本站所提供的圖片等素材,版權(quán)歸原作者所有,如需使用,請(qǐng)與原作者聯(lián)系。

上一篇:Python ftp client 處理含有中文的文件名

下一篇:JS判斷字符串長(zhǎng)度的5個(gè)方法