草庐IT

android - Android 中调用 https web 服务的方法

coder 2023-12-26 原文

您好,我正在开发 Android 应用程序,我需要调用使用 https 协议(protocol)的 Web 服务。我能够调用简单的基于 http 协议(protocol)的 Web 服务,但没有找到调用 https 的任何正确解决方案。我发现很多 stackoverflow 线程,例如 How to ignore SSL certificate errors in Apache HttpClient 4.0但他们都在绕过 SSL,这对 https 毫无意义。我不想绕过 SSL。

我正在这样做,但它不起作用。

HttpClient httpclient = new DefaultHttpClient();

// Prepare a request object
HttpGet httpget = new HttpGet(url); 

// Execute the request
HttpResponse response;
try {
    response = httpclient.execute(httpget);
    // Examine the response status
    Log.i("Praeda",response.getStatusLine().toString());

    // Get hold of the response entity
    HttpEntity entity = response.getEntity();
    // If the response does not enclose an entity, there is no need
    // to worry about connection release

    if (entity != null) {

        // A Simple JSON Response Read
        InputStream instream = entity.getContent();
        String result= convertStreamToString(instream);
        // now you have the string representation of the HTML request
        instream.close();
    }


} catch (Exception e) {}

请帮我做这件事。提前致谢。

最佳答案

这是完整的解决方案。我已经为我的申请写了这个。

/**
 * This Activity is being used to show an alert about certificate exception
 * while communicating to server. User can take action on the alert and
 * {@link X509Certificate} will be added to trust zone if user proceed.
 */
public class SSLCertificateErrorDialogActivity extends Activity {

    private static final String TAG = SSLCertificateErrorDialogActivity.class
            .getSimpleName();
    /** Key to send certificate via Intent between activities */
    private static final String CERTIFICATE_INTENT_EXTRA = "ssl_certificate";
    /** Key to send failing url via Intent between activities */
    private static final String FAILING_URL_INTENT_EXTRA = "failing_url";
    /** Request code for install certificate */
    private static final int INSTALL_CERTIFICATE = 100;
    private AlertDialog mCertificateDialog;
    /**
     * Certificate which needs to added to trust zone.
     */
    private X509Certificate mX509Certificate;
    /**
     * Url which is being failed for the SSL handshake
     */
    private String mFailingUrl;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // This is UI less Activity. Layout should not be set.
        // Read certificate intent and install
        handleIntent(getIntent());
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        handleIntent(intent);
    }

    private void handleIntent(Intent intent) {
        if (intent == null) {
            Log.d(TAG, "Can not show dialog, intent is null");
            finish();
            return;
        }
        this.mX509Certificate = (X509Certificate) intent
                .getSerializableExtra(CERTIFICATE_INTENT_EXTRA);
        this.mFailingUrl = (String) intent.getStringExtra(FAILING_URL_INTENT_EXTRA);
        if ((this.mX509Certificate == null) || (this.mFailingUrl == null)) {
            Log.d(TAG,
                    "Can not show dialog, certificate or failingurl is null");
            finish();
            return;
        }
        // Inform user for certificate error
        if ((mCertificateDialog == null)
                || (mCertificateDialog.isShowing() == false)) {
            // Show dialog only when if it it not showing.
            // Certificate will be updated, and will be read
            // from dialog when click on ok. So no need to
            // dismiss current dialog.
            showSSLCertificateAcceptDialog();
        }
    }

    @Override
    public void onBackPressed() {
        // Prevent back press
    }

    @Override
    protected void onDestroy() {
        if ((mCertificateDialog != null)
                && (mCertificateDialog.isShowing() == true)) {
            mCertificateDialog.dismiss();
        }
        super.onDestroy();
    }

    /**
     * Shows an alert dialog about SSL certificate issue. If user proceed,
     * certificate will be added to trust zone, and this dialog will not be
     * shown for same certificate.
     */
    private void showSSLCertificateAcceptDialog() {

        AlertDialog.Builder builder = new AlertDialog.Builder(
                SSLCertificateErrorDialogActivity.this);
        builder.setIcon(R.drawable.abouthp_icon);
        builder.setTitle(R.string.untrusted_cert_dialog_title);
        builder.setMessage(msg);
        builder.setPositiveButton(R.string.untrusted_cert_dialog_action_ok,
                new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int id) {
                        installCertificate();
                    }
                });
        builder.setNegativeButton(R.string.untrusted_cert_dialog_action_cancel,
                new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int id) {
                        dialog.dismiss();
                        // TODO Retry the failing url
                        finish();
                    }
                });
        mCertificateDialog = builder.create();
        mCertificateDialog.setCancelable(false);
        mCertificateDialog.show();
    }

    /**
     * Install {@link X509Certificate} to trust zone. First this method will try
     * to add certificate from background and on fail it will show a dialog to
     * add certificate. This method must be called from an Activity, as it need
     * an activity instance.
     */
    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
    private void installCertificate() {
        X509Certificate certificate = SSLCertificateErrorDialogActivity.this.mX509Certificate;
        if (certificate != null) {
            byte[] encodedCert = null;
            try {
                encodedCert = certificate.getEncoded();
            } catch (CertificateEncodingException e) {
                e.printStackTrace();
            }
            if (encodedCert != null) {
                installUsingIntent(encodedCert, INSTALL_CERTIFICATE);
            }
        } else {
            // TODO Retry the failing url
            finish();
        }
    }

    /**
     * Install certificate to trust zone using intent. User action will be
     * required while installing.
     * 
     * @param encodedCert
     *            of {@link X509Certificate}
     * @param requestCode
     */
    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
    private void installUsingIntent(byte[] encodedCert, int requestCode) {
        Intent intent = KeyChain.createInstallIntent();
        // Default Alias name. User can change it.
        intent.putExtra(KeyChain.EXTRA_NAME, "MY Certificate");
        intent.putExtra(KeyChain.EXTRA_CERTIFICATE, encodedCert);
        startActivityForResult(intent, requestCode);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch (requestCode) {
        case INSTALL_CERTIFICATE:
            // No matter if action was success or not, retry to connect with
            // failed url and finish this activity.
            // You can retry the failiing url
            finish();
            break;

        default:
            break;
        }
    }

    /**
     * Show {@link SSLCertificateErrorDialogActivity} to inform user that, while
     * communicating to server there is untrusted certificate exception. User
     * can take action, certificate will be added to trust zone if user proceed.
     * 
     * @param context
     * @param certificate
     *            {@link X509Certificate} to be added to trust zone.
     * @param failingUrl
     *            is an url for SSL certificate error occurred, purpose of this
     *            url is to retry the same url after user action either
     *            cancelled or proceed.
     */
    public static void show(Context context, X509Certificate certificate,
            String failingUrl) {
        Context appContext = context.getApplicationContext();
        Intent intent = new Intent(appContext,
                SSLCertificateErrorDialogActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
        intent.putExtra(CERTIFICATE_INTENT_EXTRA, certificate);
        intent.putExtra(FAILING_URL_INTENT_EXTRA, failingUrl);
        appContext.startActivity(intent);
    }
}

这是帮助您处理 SSL 证书错误并安装到设备的实用程序类

import java.io.IOException;
import java.net.Socket;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Enumeration;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

import org.apache.http.client.HttpClient;
import org.apache.http.conn.ClientConnectionManager;
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.conn.ssl.AllowAllHostnameVerifier;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;

import android.content.Context;
import android.util.Log;

/**
 * This class will perform all network related calls like post, get and put.
 */
public class NetworkUtility {
    protected static final String TAG = NetworkUtility.class.getSimpleName();
    /**
     * Connection timeout. 15 seconds
     */
    private static final int HTTP_CONNECTION_TIMEOUT = 150000;

    /**
     * Returns Default HTTP client with socket factories initialised.
     * 
     * @param context
     * @param targetUrl
     *            to do request
     * @return Default HTTP Client
     */
    private static HttpClient getDefaultHttpClient(Context context,
            String targetUrl) {
        HttpParams params = new BasicHttpParams();
        HttpConnectionParams.setConnectionTimeout(params,
                HTTP_CONNECTION_TIMEOUT);
        HttpConnectionParams.setSoTimeout(params, HTTP_CONNECTION_TIMEOUT);
        try {
            SchemeRegistry registry = new SchemeRegistry();
            registry.register(new Scheme("http", PlainSocketFactory
                    .getSocketFactory(), 80));
            registry.register(new Scheme("https", new MySSLSocketFactory(
                    context.getApplicationContext(), targetUrl), 443));
            ClientConnectionManager ccm = new ThreadSafeClientConnManager(
                    params, registry);
            return new DefaultHttpClient(ccm, params);
        } catch (Exception e) {
            e.printStackTrace();
            return new DefaultHttpClient(params);
        }
    }

    /**
     * TrustManager to accept all certificates. It does not do any certificates
     * validation.
     * 
     * TODO: Once we have actual certificates this implementation should be
     * changed accordingly.
     */
    private static class MyTrustManager implements X509TrustManager {
        private X509TrustManager mOriginalX509TrustManager;
        private Context mContext;
        private String mTargetUrl;

        /**
         * @param context
         *            - application context.
         * @param targetUrl
         *            - to do request.
         */
        public MyTrustManager(Context context, String targetUrl) {
            try {
                this.mContext = context;
                this.mTargetUrl = targetUrl;
                TrustManagerFactory originalTrustManagerFactory = TrustManagerFactory
                        .getInstance("X509");
                originalTrustManagerFactory.init((KeyStore) null);
                TrustManager[] originalTrustManagers = originalTrustManagerFactory
                        .getTrustManagers();
                this.mOriginalX509TrustManager = (X509TrustManager) originalTrustManagers[0];
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        public void checkClientTrusted(X509Certificate[] cert, String authType)
                throws CertificateException {
        }

        public void checkServerTrusted(X509Certificate[] cert, String authType)
                throws CertificateException {
            try {
                // Verify if the certificate has been trusted.
                // This validation will pass if certificate has
                // been added by user or system.
                mOriginalX509TrustManager.checkServerTrusted(cert, authType);
            } catch (CertificateException originalException) {
                // Certificate has not present into trust zone.
                // Find first certificate from the array of certificates which
                // needs to install.
                X509Certificate certificate = getCertificateToInstall(cert);
                Log.d(TAG, "Showing dialog for certificate exception...");
                // Show dialog where user can install this certificate
                SSLCertificateErrorDialogActivity.show(this.mContext,
                        certificate, this.mTargetUrl);
                throw originalException;
            }
        }

        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }
    }

    /**
     * Get certificate to be installed from the given list of certificates. It
     * iterates all certificates from CA and if a certificate, from the given
     * array is not present into CA, this method returns that certificate.
     * 
     * @param certificates
     * @return {@link X509Certificate} to install.
     */
    private static X509Certificate getCertificateToInstall(
            X509Certificate[] certificates) {
        X509Certificate result = null;
        try {
            KeyStore ks = KeyStore.getInstance("AndroidCAStore");
            if (ks != null) {
                ks.load(null, null);
                boolean certFound = false;
                for (X509Certificate certificate : certificates) {
                    Enumeration<String> aliases = ks.aliases();
                    while (aliases.hasMoreElements()) {
                        String alias = (String) aliases.nextElement();
                        X509Certificate cert = (X509Certificate) ks
                                .getCertificate(alias);
                        if (certificate.equals(cert) == true) {
                            certFound = true;
                            break;
                        }
                    }
                    if (certFound == false) {
                        Log.d(TAG, "Not found certificate");
                        // Need to install this certificate
                        result = certificate;
                        break;
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }


    private static class MySSLSocketFactory extends SSLSocketFactory {
        private javax.net.ssl.SSLSocketFactory mFactory;

        public MySSLSocketFactory(Context context, String targetUrl)
                throws KeyManagementException, NoSuchAlgorithmException,
                KeyStoreException, UnrecoverableKeyException {
            super((KeyStore) null);
            try {
                SSLContext sslcontext = SSLContext.getInstance("TLS");
                sslcontext.init(null, new TrustManager[] { new MyTrustManager(
                        context, targetUrl) }, null);
                mFactory = sslcontext.getSocketFactory();
                setHostnameVerifier(new AllowAllHostnameVerifier());
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }

        @Override
        public Socket createSocket() throws IOException {
            return mFactory.createSocket();
        }

        @Override
        public Socket createSocket(Socket socket, String s, int i, boolean flag)
                throws IOException {
            return mFactory.createSocket(socket, s, i, flag);
        }
    }
}

使用非常简单如下

HttpGet httpGet = new HttpGet(url);
HttpClient httpClient = getDefaultHttpClient(context, url);
HttpResponse response = httpClient.execute(httpGet);

关于android - Android 中调用 https web 服务的方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24624439/

有关android - Android 中调用 https web 服务的方法的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  3. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  4. ruby - 使用 ruby​​ 和 savon 的 SOAP 服务 - 2

    我正在尝试使用ruby​​和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我

  5. ruby - Facter::Util::Uptime:Module 的未定义方法 get_uptime (NoMethodError) - 2

    我正在尝试设置一个puppet节点,但ruby​​gems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由ruby​​gems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby

  6. ruby - 具有身份验证的私有(private) Ruby Gem 服务器 - 2

    我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..

  7. Ruby 方法() 方法 - 2

    我想了解Ruby方法methods()是如何工作的。我尝试使用“ruby方法”在Google上搜索,但这不是我需要的。我也看过ruby​​-doc.org,但我没有找到这种方法。你能详细解释一下它是如何工作的或者给我一个链接吗?更新我用methods()方法做了实验,得到了这样的结果:'labrat'代码classFirstdeffirst_instance_mymethodenddefself.first_class_mymethodendendclassSecond使用类#returnsavailablemethodslistforclassandancestorsputsSeco

  8. ruby-on-rails - Rails 3.2.1 中 ActionMailer 中的未定义方法 'default_content_type=' - 2

    我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer

  9. ruby - Highline 询问方法不会使用同一行 - 2

    设置:狂欢ruby1.9.2高线(1.6.13)描述:我已经相当习惯在其他一些项目中使用highline,但已经有几个月没有使用它了。现在,在Ruby1.9.2上全新安装时,它似乎不允许在同一行回答提示。所以以前我会看到类似的东西:require"highline/import"ask"Whatisyourfavoritecolor?"并得到:Whatisyourfavoritecolor?|现在我看到类似的东西:Whatisyourfavoritecolor?|竖线(|)符号是我的终端光标。知道为什么会发生这种变化吗? 最佳答案

  10. ruby - 主要 :Object when running build from sublime 的未定义方法 `require_relative' - 2

    我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby​​1.9+ 关于ruby-主要:Objectwhenrun

随机推荐