Integrating HTTP and HTTPS Connection


Introduction

這篇文章,主要討論 Android 程式如何進行 HTTP 與 HTTPS 要求的作業程序, 在手機平台上,大多數的應用程式都是以主從架構(Client/Server) 的方式,透過HTTP以及HTTPS的通訊協定,來進行傳輸通訊.
In this article I have discussed the procedure to request HTTP and HTTPS requests in android. In mobiles, most of applications based on client server communication through HTTP or HTTPS protocol,

因此你的HTTP模組最好能夠遵循物件導向的模式,由應用程式中或package中分離成幾個獨立的模組出來, 這對大型或是小型的應用程式開發效率,來說是很關鍵的一個部分.
so it is essential for a small or a large sized application that your HTTP module follows the complete object oriented and has a separate coupled module from other package of application.

這份文件主要處理的是使用一個單一的類別處理兩種類型的要求(Request)(包含HTTP及HTTPS),通常開發者會將HTTP及HTTPS作成兩個不同的類別,不過在本文中我們主要感興趣的是我們將把整合兩個類別成為一個單一的類別,開發者只要調用一個類別,實現(implement)一個監聽來取得要求伺服器後,伺服器傳回來的訊息.
Focus in this article is that an only single class handles both types of request (HTTP and HTTPS), normally developers handle the HTTP and HTTPS in two different classes, but in this in potent interest, I have handled it in a single class. Developer will need to invoke a class and implement a listener for getting the response as a notification.

Background

Steps involved:

String urlString = “HTTP://www.google.com”;

List<NameValuePair> requestParameter= new
List<NameValuePair>();

NameValuePair namVaulePair = new
NameValuePair(“name”,”ravindra”);

requestParameter .add(namVaulePair);

int reqId = 100;
HTTPHandler handler = new HTTPHandler(urlString, requestParameter,null,reqId);

Handler.addHTTPListenr(‘reference of that class implement HTTPListener’); 
Hdler.sendRequest();

Using the code

There are five classes in this demo project, divided into two packages one is UI package there from you enter URL and tap on request button and send request.

HTTPHandler: This class handles the request of HTTP:

HTTPHandler(String urlstring, final List<NameValuePair> requestParameters,final 
  Hashtable<String, String> header, int reqId)

User: first call the constructor and pass required parameter.

urlStirng: URL for HTTP request for example ‘HTTP://www.google.com’

requestParameters: if request method types is ‘POST’ then user set the list of parameters in form of NameValuePair otherwise It should be null if request method type is ‘GET’.

header: it contain the header you want to set in each HTTP request.

reqId : unique identifier of HTTP request.

getReqID(): it return the unique request id which used in HTTP request.

getURL(): return the URL used in HTTP request.

getResponse(): return the response return by requested server.

getResCode(): it return the HTTP status line. If return 200 then request is successful another wise it fail due to server reason. or invalid request by client.

addHTTPListener: add the concrete class which implement the HTTPListener class and override notifyResponse() for handle response return by server.

sendRequest(): this method execute the HTTP request.

HTTPHandler class code:

package com.brickred.HTTP;
 
import java.io.IOException;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.List;
import org.apache.HTTP.HTTPEntity;
import org.apache.HTTP.HTTPResponse;
import org.apache.HTTP.HTTPVersion;
import org.apache.HTTP.NameValuePair;
import org.apache.HTTP.client.ClientProtocolException;
import org.apache.HTTP.client.HTTPClient;
import org.apache.HTTP.client.ResponseHandler;
import org.apache.HTTP.client.entity.UrlEncodedFormEntity;
import org.apache.HTTP.client.methods.HTTPGet;
import org.apache.HTTP.client.methods.HTTPPost;
import org.apache.HTTP.conn.ClientConnectionManager;
import org.apache.HTTP.conn.params.ConnManagerPNames;
import org.apache.HTTP.conn.params.ConnPerRouteBean;
import org.apache.HTTP.conn.scheme.PlainSocketFactory;
import org.apache.HTTP.conn.scheme.Scheme;
import org.apache.HTTP.conn.scheme.SchemeRegistry;
import org.apache.HTTP.entity.StringEntity;
import org.apache.HTTP.impl.client.DefaultHTTPClient;
import org.apache.HTTP.impl.conn.SingleClientConnManager;
import org.apache.HTTP.params.BasicHTTPParams;
import org.apache.HTTP.params.CoreConnectionPNames;
import org.apache.HTTP.params.HTTPParams;
import org.apache.HTTP.params.HTTPProtocolParams;
import org.apache.HTTP.util.EntityUtils;
import android.content.Context;
import android.util.Log;

public class HTTPHandler {
    /**
     * refrence of HTTPListener interface
     */
    HTTPListner HTTPListener;
 
    /**
      * url for example
        HTTP://wwww.google.com
      */
 
    String urlstring = "";
 
    /**
      * past request parameter items
      */
 

    List<NameValuePair> postRequestParameters = null;
    /**
     * HTTP unique reqest id
     */
    int reqId = 0;
    /**
      * hold the HTTP response
      */
 
    String resMessage = "No Response Please check Url or it may be HTTPS certificate issue.";
 
    /**
     * response code
     */

    int resCode = -1;
    Hashtable<String, String> header = null;
 
    /**
      * @param urlstring
      * requested url
      * @param requestParameters
      * list post parameters if get request then null
      * @param header
      * list of header
      * @param reqId
      * url request id
      */
    public HTTPHandler(String urlstring,
                     final List<NameValuePair> requestParameters,
                     final Hashtable<String, String> header, int reqId) {
 
        this.urlstring = urlstring;
        this.postRequestParameters = requestParameters;
        this.reqId = reqId;
        this.header = header;
    }
 
    /**
      * @return reqest id for request
      */
 
    public int getReqId() {
        return reqId;
    }

    /**
      * Return requested url
      * 
      * @return
      */
    public String getURL() {
        return urlstring;
    }

    /**
      * @return the response
      */
 
    public String getResponse() {
       return resMessage;
    }

    /**
      * Return Response Code
      * 
      * @return
      */
 
    public int getResCode() {
        return resCode;
    }
 
    /**
      * @param HTTPListener
      * add the listener for notify the response
      */
 
    public void addHTTPLisner(HTTPListner HTTPListener) {
        this.HTTPListener = HTTPListener;
    }

    /**
      * send the HTTP or HTTPS request
      */
 
    public void sendRequest() {
        // TODO Auto-generated method stub
        try {
            SchemeRegistry schemeRegistry = new SchemeRegistry();
            schemeRegistry.register(new Scheme("HTTP", PlainSocketFactory.getSocketFactory(), 80));
            schemeRegistry.register(new Scheme("HTTPS", new EasySSLSocketFactory(), 443));
            HTTPParams params = new BasicHTTPParams();
 

            params.setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 50000);
            params.setParameter(ConnManagerPNames.MAX_TOTAL_CONNECTIONS, 30);
            params.setParameter(ConnManagerPNames.MAX_CONNECTIONS_PER_ROUTE, new ConnPerRouteBean(30));
            params.setParameter(HTTPProtocolParams.USE_EXPECT_CONTINUE, false);
            HTTPProtocolParams.setVersion(params, HTTPVersion.HTTP_1_1);
            ClientConnectionManager cm = new SingleClientConnManager(params, schemeRegistry);
             

            HTTPClient HTTPclient = new DefaultHTTPClient(cm, params);
 
            // DefaultHTTPClient HTTPclient = null;
            if (postRequestParameters != null) {// //////// for post request
                          // POST the envelope
 
                HTTPPost HTTPpost = new HTTPPost(urlstring);
 
                if (header != null) {
                    Enumeration enums = header.keys();
                    while (enums.hasMoreElements()) {
                        String key = (String) enums.nextElement();
                        String value = header.get(key);
                        HTTPpost.addHeader(key, value);
                    }
                }
 
                HTTPpost.setEntity(new UrlEncodedFormEntity(postRequestParameters));
                // Response handler
                ResponseHandler<String> reshandler = new ResponseHandler<String>() {
                // invoked when client receives response
                public String handleResponse(HTTPResponse response)

                throws ClientProtocolException, IOException {
                    // get response entity
                    HTTPEntity entity = response.getEntity();
 
                    // get response code
                    resCode = response.getStatusLine().getStatusCode();

                    // read the response as byte array
                    StringBuffer out = new StringBuffer();
 
                    byte[] b = EntityUtils.toByteArray(entity);
                    // write the response byte array to a string buffer
                    out.append(new String(b, 0, b.length));
 
                    return out.toString();
                }
            };
 
            resMessage = HTTPclient.execute(HTTPpost, reshandler);
            // Log.d("", "Response=====" + resMessage);
        }
        else {// ///////// for get Request
            ResponseHandler<String> responsehandler = new ResponseHandler<String>() {
                @Override
                    public String handleResponse(HTTPResponse response)
                        throws ClientProtocolException, IOException {
                            // TODO Auto-generated method stub
                            HTTPEntity entity = response.getEntity();
                            
                            // get response code
                            resCode = response.getStatusLine().getStatusCode();
 
                            // read the response as byte array
                            StringBuffer out = new StringBuffer();
 
                            byte[] b = EntityUtils.toByteArray(entity);
                            // write the response byte array to a string buffer
                            out.append(new String(b, 0, b.length));
 
                            return out.toString();
                        }
                    };
 
                    HTTPGet HTTPget = new HTTPGet(urlstring);
                    resMessage = HTTPclient.execute(HTTPget, responsehandler);
                }

                // close the connection
                HTTPclient.getConnectionManager().shutdown();
            }
            catch (Exception e) {
                Log.i("connection Exeception", e.getMessage());
            }
            finally {
                HTTPListener.notifyHTTPRespons(this);
            }
        }
    }

HTTPListener: This listener must be implement and override the single abstract method notifyResponse() for get the response generated by HTTP request and know the status of request.

Code:

package com.brickred.HTTP;

/**
 * @author ravindrap
 * HTTPListener is super class of which set the HTTP or  HTTPS request 
 */
 
public interface HTTPListner {
    /**
     * @param HTTP
     * HTTP handler object. when HTTP request is completed then is call in HTTPHandler class
     */

    void notifyHTTPRespons(HTTPHandler HTTP);
}

EasySSlSocketFactory: This socket factory class will create the self signed certificate.

package com.testHTTPS;

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 * HTTP://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES or CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
 
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManager;
import org.apache.HTTP.conn.ConnectTimeoutException;
import org.apache.HTTP.conn.scheme.LayeredSocketFactory;
import org.apache.HTTP.conn.scheme.SocketFactory;
import org.apache.HTTP.params.HTTPConnectionParams;
import org.apache.HTTP.params.HTTPParams;

/**
 * This socket factory will create ssl socket that accepts self signed
 * certificate
 * 
 * @author olamy
 * @version $Id:
EasySSLSocketFactory.java 765355 2009-04-15 20:59:07Z evenisse

 *          $
 * @since 1.2.3
 */
 
public class EasySSLSocketFactory implements SocketFactory, LayeredSocketFactory {

    private SSLContext sslcontext = null; 
    private static SSLContext createEasySSLContext() throws IOException {
        try {
            SSLContext context = SSLContext.getInstance("TLS");
            context.init(null, new TrustManager[] { new EasyX509TrustManager(null) }, null);
            return context;
        } catch (Exception e) {
             throw new IOException(e.getMessage());
    }
}

private SSLContext getSSLContext() throws IOException {
    if (this.sslcontext == null) {
        this.sslcontext = createEasySSLContext();
    }

    return this.sslcontext;
}

/**
 * @see org.apache.HTTP.conn.scheme.SocketFactory#connectSocket(java.net.Socket,
 *      java.lang.String, int, java.net.InetAddress, int,
 *      org.apache.HTTP.params.HTTPParams)
 */
 
public Socket connectSocket(Socket sock, String host, int port, InetAddress localAddress, int localPort, HTTPParams params)

    throws IOException, UnknownHostException, ConnectTimeoutException {
        int connTimeout = HTTPConnectionParams.getConnectionTimeout(params);
        int soTimeout = HTTPConnectionParams.getSoTimeout(params);
         
        InetSocketAddress remoteAddress = new InetSocketAddress(host, port);
        SSLSocket sslsock = (SSLSocket) ((sock != null) ? sock : createSocket());
 
     if ((localAddress != null) || (localPort > 0)) {
         // we need to bind explicitly
         if (localPort < 0) {
             localPort = 0; // indicates "any"
         }
         InetSocketAddress isa = new InetSocketAddress(localAddress, localPort);
         sslsock.bind(isa);
     }
     sslsock.connect(remoteAddress, connTimeout);
     sslsock.setSoTimeout(soTimeout);
     return sslsock;
}
 
/**
 * @see org.apache.HTTP.conn.scheme.SocketFactory#createSocket()
 */
 
public Socket createSocket() throws IOException {
    return getSSLContext().getSocketFactory().createSocket();
}

/**
 * @see org.apache.HTTP.conn.scheme.SocketFactory#isSecure(java.net.Socket)
 */
 
public boolean isSecure(Socket socket) throws IllegalArgumentException {
    return true;
}

/**
 * @see org.apache.HTTP.conn.scheme.LayeredSocketFactory#createSocket(java.net.Socket,
 *      java.lang.String, int, boolean)
 */
 
public Socket createSocket(Socket socket, String host, int port, boolean autoClose)
   throws IOException, UnknownHostException {
       return getSSLContext().getSocketFactory().createSocket(socket, host, port, autoClose);
 
       //return getSSLContext().getSocketFactory().createSocket();
}

// -------------------------------------------------------------------
// javadoc in org.apache.HTTP.conn.scheme.SocketFactory says :
// Both Object.equals() and Object.hashCode() must be overridden
// for the correct operation of some connection managers
// -------------------------------------------------------------------
 
public boolean equals(Object obj) {
    return ((obj != null) && obj.getClass().equals(EasySSLSocketFactory.class));
}
 
public int hashCode() {
    return EasySSLSocketFactory.class.hashCode();
}
}

Class EasyX509TrustManager code: 

package com.brickred.HTTP;

/* 
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 * HTTP://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES or CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory; 
import javax.net.ssl.X509TrustManager;

/**
 * @author olamy
 * @version $Id:
EasyX509TrustManager.java 765355 2009-04-15 20:59:07Z evenisse $
 * @since 1.2.3
 */

public class EasyX509TrustManager
   implements X509TrustManager
{
    private X509TrustManager standardTrustManager = null;

   /**
    * Constructor for EasyX509TrustManager.
    */
    public EasyX509TrustManager( KeyStore keystore )
        throws NoSuchAlgorithmException, KeyStoreException
        {
            super();
            TrustManagerFactory factory = TrustManagerFactory.getInstance( 
                TrustManagerFactory.getDefaultAlgorithm() );
        
            factory.init( keystore );
            TrustManager[] trustmanagers = factory.getTrustManagers();
 
            if ( trustmanagers.length == 0 )
            {
               throw new NoSuchAlgorithmException( "no trust manager found" );
            }
            this.standardTrustManager = (X509TrustManager) trustmanagers[0];
        }
       /**
        * @see javax.net.ssl.X509TrustManager#checkClientTrusted(X509Certificate[],String authType)
        */
 
       public void checkClientTrusted(X509Certificate[] certificates, String authType )

           throws CertificateException
           {
               standardTrustManager.checkClientTrusted( certificates, authType );
           }
       /**
        * @see javax.net.ssl.X509TrustManager#checkServerTrusted(X509Certificate[],String authType)
        */
        public void checkServerTrusted(X509Certificate[] certificates, String authType )
            throws CertificateException
            {
                if ( ( certificates != null) && ( certificates.length == 1 ) )
                {
                     certificates[0].checkValidity();
                } 
                else
                { 
                    standardTrustManager.checkServerTrusted( certificates, authType );
                }
           }
           /**
            * @see javax.net.ssl.X509TrustManager#getAcceptedIssuers()
            */
 
           public X509Certificate[] getAcceptedIssuers()
           {
             return this.standardTrustManager.getAcceptedIssuers();
           }
        }
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="HTTP://schemas.android.com/apk/res/android"
      package="com.brickred" 
      android:versionCode="1"
      android:versionName="1.0">
    <uses-sdk android:minSdkVersion="4" />

    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name="com.brickred.activity.HTTPConnectionApiActivity"
                  android:label="@string/app_name">
            <intent-filter> 
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter> 
        </activity>

    </application>
    <uses-permission android:name="android.permission.INTERNET"/>
</manifest>

HTTPConnectionApiActivity.java

package com.brickred.activity;


import android.app.Activity;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import com.brickred.R;
import com.brickred.HTTP.HTTPHandler;
import com.brickred.HTTP.HTTPListner;

public class HTTPConnectionApiActivity extends Activity implements HTTPListner{
    /** Called when the activity is first created. */
Handler handler = null;
TextView textviewResponse;
ProgressDialog progressDialog;
EditText edtTextUrl = null;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        Button buttonClickMe = (Button)findViewById(R.id.btnclick);
        textviewResponse= (TextView)findViewById(R.id.txtshow);
        edtTextUrl= (EditText)findViewById(R.id.txturl);
        handler = new Handler();
        progressDialog = new ProgressDialog(this);
        
        buttonClickMe.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
// TODO Auto-generated method stub
//Log.i("", msg)
if(edtTextUrl.getText().length() > 0 && edtTextUrl.getText().toString().startsWith("HTTP")){ 
progressDialog.setMessage("Please wait for response ... ");
progressDialog.show();
new Thread(new Runnable() {

@Override
public void run() {
// TODO Auto-generated method stub
HTTPHandler handler = new HTTPHandler(edtTextUrl.getText().toString().trim(),null, null, 123);
handler.addHTTPLisner(HTTPConnectionApiActivity.this);
handler.sendRequest();
}
}).start();
}else{
showAlert("Error", "Please enter valid url", null, "Ok");
}

}
});
}

@Override
public void notifyHTTPRespons(final HTTPHandler HTTP) {
// TODO Auto-generated method stub
progressDialog.cancel();
Log.i("Log", "responce ==  "+HTTP.getResCode());
handler.post(new Runnable() {

@Override
public void run() {
// TODO Auto-generated method stub
textviewResponse.setText("");
textviewResponse.setText(HTTP.getResponse());
}
});
}
/**
* @param title
* @param Message
* @param NegButton
* @param posButton
*/
private void showAlert(String title,String Message, final String NegButton,
final String posButton) {

AlertDialog.Builder alertBuilder = new Builder(this);
alertBuilder.setTitle(title);
alertBuilder.setMessage(Message);
if (NegButton != null) {
alertBuilder.setNegativeButton(NegButton,
new DialogInterface.OnClickListener() {

public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub

}
});
}
if (posButton != null) {
alertBuilder.setPositiveButton(posButton,
new DialogInterface.OnClickListener() {

public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub

}
});
}
AlertDialog alert = alertBuilder.create();
alert.show();

}
}

Points of Interest

Interesting point in this article is user no need to write a difference code for HTTP and HTTPS protocol. User need only just enter the the URL as per as his/her requirement and send the request and its works on multithreading environment. User can send multiple request at that same time without waiting the previous request completion.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)






文章来自: 本站原创
引用通告: 查看所有引用 | 我要引用此文章
Tags: Android 教學
相關日誌:

评论: 0 | 引用: 0 | 查看次数: 1374
发表评论
昵 称:
密 码: 游客发言不需要密码.
内 容:
验证码: 验证码
选 项:
虽然发表评论不用注册,但是为了保护您的发言权,建议您注册帐号.
字数限制 1000 字 | UBB代码 关闭 | [img]标签 关闭