您好,我正在开发 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/
我正在学习如何使用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
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
类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
我正在尝试使用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请求没有正确的命名空间。任何人都可以建议我
我正在尝试设置一个puppet节点,但rubygems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由rubygems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby
我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..
我想了解Ruby方法methods()是如何工作的。我尝试使用“ruby方法”在Google上搜索,但这不是我需要的。我也看过ruby-doc.org,但我没有找到这种方法。你能详细解释一下它是如何工作的或者给我一个链接吗?更新我用methods()方法做了实验,得到了这样的结果:'labrat'代码classFirstdeffirst_instance_mymethodenddefself.first_class_mymethodendendclassSecond使用类#returnsavailablemethodslistforclassandancestorsputsSeco
我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>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
设置:狂欢ruby1.9.2高线(1.6.13)描述:我已经相当习惯在其他一些项目中使用highline,但已经有几个月没有使用它了。现在,在Ruby1.9.2上全新安装时,它似乎不允许在同一行回答提示。所以以前我会看到类似的东西:require"highline/import"ask"Whatisyourfavoritecolor?"并得到:Whatisyourfavoritecolor?|现在我看到类似的东西:Whatisyourfavoritecolor?|竖线(|)符号是我的终端光标。知道为什么会发生这种变化吗? 最佳答案
我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby1.9+ 关于ruby-主要:Objectwhenrun