本文将为您提供关于Android8:不允许明文HTTP流量的详细介绍,我们还将为您解释安卓11不允许访问data的相关知识,同时,我们还将为您提供关于Android8:不允许使用CleartextHT
本文将为您提供关于Android 8:不允许明文 HTTP 流量的详细介绍,我们还将为您解释安卓11不允许访问data的相关知识,同时,我们还将为您提供关于Android 8:不允许使用Cleartext HTTP流量、android httpClient (https/http) 的优化构建方式二、android httpClient(https/http)的优化构建方式一、Android HTTPPost返回错误“方法不允许”的实用信息。
本文目录一览:- Android 8:不允许明文 HTTP 流量(安卓11不允许访问data)
- Android 8:不允许使用Cleartext HTTP流量
- android httpClient (https/http) 的优化构建方式二
- android httpClient(https/http)的优化构建方式一
- Android HTTPPost返回错误“方法不允许”
Android 8:不允许明文 HTTP 流量(安卓11不允许访问data)
我收到来自 Android 8 用户的报告,称我的应用(使用后端提要)不显示内容。经过调查,我发现 Android 8 上发生了以下异常:
08-29 12:03:11.246 11285-11285/ E/: [12:03:11.245,main]: Exception: IOException java.io.IOException: Cleartext HTTP traffic to * not permitted
at com.android.okhttp.HttpHandler$CleartextURLFilter.checkURLPermitted(HttpHandler.java:115)
at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:458)
at com.android.okhttp.internal.huc.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:127)
at com.deiw.android.generic.tasks.AbstractHttpAsyncTask.doConnection(AbstractHttpAsyncTask.java:207)
at com.deiw.android.generic.tasks.AbstractHttpAsyncTask.extendedDoInBackground(AbstractHttpAsyncTask.java:102)
at com.deiw.android.generic.tasks.AbstractAsyncTask.doInBackground(AbstractAsyncTask.java:88)
at android.os.AsyncTask$2.call(AsyncTask.java:333)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
at java.lang.Thread.run(Thread.java:764)
(我已经删除了包名、URL 和其他可能的标识符)
在 Android 7 及更低版本上一切正常,我没有android:usesCleartextTraffic
在 Manifest 中进行设置(并且将其设置为true
无济于事,无论如何这是默认值),我也没有使用网络安全信息。如果我调用NetworkSecurityPolicy.getInstance().isCleartextTrafficPermitted()
,它会返回false
Android 8,true
对于旧版本,使用相同的 apk 文件。我试图在有关 Android O 的 Google 信息中找到一些提及,但没有成功。
Android 8:不允许使用Cleartext HTTP流量
我收到了Android 8用户的报告,我的应用(使用后端Feed)没有显示内容.经过调查,我发现在Android 8上发生以下异常:
08-29 12:03:11.246 11285-11285/ E/: [12:03:11.245, main]: Exception: IOException java.io.IOException: Cleartext HTTP traffic to * not permitted
at com.android.okhttp.HttpHandler$CleartextURLFilter.checkURLPermitted(HttpHandler.java:115)
at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:458)
at com.android.okhttp.internal.huc.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:127)
at com.deiw.android.generic.tasks.AbstractHttpAsyncTask.doConnection(AbstractHttpAsyncTask.java:207)
at com.deiw.android.generic.tasks.AbstractHttpAsyncTask.extendedDoInBackground(AbstractHttpAsyncTask.java:102)
at com.deiw.android.generic.tasks.AbstractAsyncTask.doInBackground(AbstractAsyncTask.java:88)
at android.os.AsyncTask$2.call(AsyncTask.java:333)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
at java.lang.Thread.run(Thread.java:764)
(我删除了包名,URL和其他可能的标识符)
在Android 7及更低版本上一切正常,我没有在Manifest中设置android:usesCleartextTraffic(并将其设置为true无效,无论如何都是默认值),我也不使用网络安全信息.如果我调用NetworkSecurityPolicy.getInstance().isCleartextTrafficPermitted(),它将为Android 8返回false,对于旧版本,则返回true,使用相同的apk文件.
我试图在关于Android O的Google信息上找到一些提及,但没有成功.
解决方法:
根据Network security configuration –
Starting with Android 9 (API level 28), cleartext support is disabled
by default.
另外看看 – https://koz.io/android-m-and-the-war-on-cleartext-traffic/
选项1 –
创建文件res / xml / network_security_config.xml –
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">Your URL(ex: 127.0.0.1)</domain>
</domain-config>
</network-security-config>
AndroidManifest.xml –
<?xml version="1.0" encoding="utf-8"?>
<manifest ...>
<uses-permission android:name="android.permission.INTERNET" />
<application
...
android:networkSecurityConfig="@xml/network_security_config"
...>
...
</application>
</manifest>
选项2 –
android:usesCleartextTraffic Doc
AndroidManifest.xml –
<?xml version="1.0" encoding="utf-8"?>
<manifest ...>
<uses-permission android:name="android.permission.INTERNET" />
<application
...
android:usesCleartextTraffic="true"
...>
...
</application>
</manifest>
另外正如@david.s’ answer指出android:targetSandBoxVersion也可能是一个问题 –
根据Manifest Docs –
android:targetSandBoxVersion
The target sandBox for this app to use. The higher the sandBox version
number, the higher the level of security. Its default value is 1; you
can also set it to 2. Setting this attribute to 2 switches the app to
a different SELinux sandBox. The following restrictions apply to a
level 2 sandBox:
- The default value of
usesCleartextTraffic
in the Network Security Config is false.- Uid sharing is not permitted.
选项3 –
如果你在< manifest>中有android:targetSandBoxVersion然后将其减少到1
AndroidManifest.xml –
<?xml version="1.0" encoding="utf-8"?>
<manifest android:targetSandBoxVersion="1">
<uses-permission android:name="android.permission.INTERNET" />
...
</manifest>
android httpClient (https/http) 的优化构建方式二
由于时间原因,这里只构建所有请求 https 都能通过的请求 client
首先定义(重写)信任管理器
public class SSLTrustManager implements javax.net.ssl.TrustManager,
javax.net.ssl.X509TrustManager ,HostnameVerifier{
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public boolean isServerTrusted(
java.security.cert.X509Certificate[] certs) {
return true;
}
public boolean isClientTrusted(
java.security.cert.X509Certificate[] certs) {
return true;
}
public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType)
throws java.security.cert.CertificateException {
return;
}
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType)
throws java.security.cert.CertificateException {
return;
}
@Override
public boolean verify(String urlHostName, SSLSession session) { //允许所有主机
return true;
}
}
然后封装
public static HttpURLConnection connect(String strUrl) throws Exception {
javax.net.ssl.TrustManager[] trustAllCerts = new javax.net.ssl.TrustManager[1];
javax.net.ssl.TrustManager tm = new SSLTrustManager();
trustAllCerts[0] = tm;
javax.net.ssl.SSLContext sc = javax.net.ssl.SSLContext
.getInstance("SSL");
sc.init(null, trustAllCerts, null);
javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(sc
.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier((HostnameVerifier) tm);
URL url = new URL(strUrl);
HttpURLConnection urlConn = (HttpURLConnection) url.openConnection();
return urlConn;
}
测试一下
public void unitest()
{
HttpURLConnection urlConn = connect(''https://github.com/'');
urlConn.setDoInput(true);
urlConn.setRequestMethod("GET");
urlConn.connect();
InputStream is = urlConn.getInputStream();
StringBuffer sb = new StringBuffer();
if(is!=null)
{
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String s = null;
while ((s=br.readLine())!=null)
{
sb.append(s).append("\n");
}
}
System.out.println("Content:\n"+sb.toString());
}
try do it!
android httpClient(https/http)的优化构建方式一
参考:基于java的https双向认证,android上亦可用
Android Https相关完全解析 当OkHttp遇到Https
在android中,经常不可避免的的使用https和http访问网络数据,因此需要先构建一个网络访问client
其中https的访问需要使用SSLSocket,但对于一般安全性要求不是很高的通信,一般设置SSLSocket是允许所有主机通过,下面给出2中,一种是允许所有主机通过的https通信,另一种是加密传输,需要使用cert证书。
允许所有主机通过
public class GlobalUtils
{
public static HttpClient getAndroidHttpClient(int connTimeout, String userAgent,int retryTimes)
{
AbstractHttpClient httpClient = null;
//设置请求控制参数
HttpParams params = new BasicHttpParams();
ConnManagerParams.setTimeout(params, connTimeout);
HttpConnectionParams.setSoTimeout(params, connTimeout);
HttpConnectionParams.setConnectionTimeout(params, connTimeout);
if (TextUtils.isEmpty(userAgent)) {
userAgent = System.getProperty("http.agents", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.124 Safari/537.36");
}
HttpProtocolParams.setUserAgent(params, userAgent);
//设置最大的连接数
ConnManagerParams.setMaxConnectionsPerRoute(params, new ConnPerRouteBean(10));
ConnManagerParams.setMaxTotalConnections(params, 10);
HttpConnectionParams.setTcpNoDelay(params, true); //关闭Socket缓冲
HttpConnectionParams.setSocketBufferSize(params, 1024 * 8);//本方法与setTcpNoDelay冲突
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
schemeRegistry.register(new Scheme("https", DefaultSSLSocketFactory.getSocketFactory(), 443));
httpClient = new DefaultHttpClient(new ThreadSafeClientConnManager(params, schemeRegistry), params);
httpClient.setHttpRequestRetryHandler(new RetryHandler(retryTimes));
httpClient.addRequestInterceptor(new HttpRequestInterceptor() {
@Override
public void process(org.apache.http.HttpRequest httpRequest, HttpContext httpContext) throws org.apache.http.HttpException, IOException {
if (!httpRequest.containsHeader("Accept-Encoding")) {
httpRequest.addHeader("Accept-Encoding", "gzip");
}
}
});
httpClient.addResponseInterceptor(new HttpResponseInterceptor() {
@Override
public void process(HttpResponse response, HttpContext httpContext) throws org.apache.http.HttpException, IOException {
final HttpEntity entity = response.getEntity();
if (entity == null) {
return;
}
final Header encoding = entity.getContentEncoding();
if (encoding != null) {
for (HeaderElement element : encoding.getElements()) {
if (element.getName().equalsIgnoreCase("gzip")) {
response.setEntity(new GZipDecompressingEntity(response.getEntity()));
return;
}
}
}
}
});
return httpClient;
}
}
上面的重试RetryHandler是请求失败后重试的规则
public class RetryHandler implements HttpRequestRetryHandler { //需要实现HttpRequestRetryHandler
private static final int RETRY_SLEEP_INTERVAL = 500;
private static HashSet<Class<?>> exceptionWhiteList = new HashSet<Class<?>>();
private static HashSet<Class<?>> exceptionBlackList = new HashSet<Class<?>>();
static {
exceptionWhiteList.add(NoHttpResponseException.class);
exceptionWhiteList.add(UnknownHostException.class);
exceptionWhiteList.add(SocketException.class);
exceptionBlackList.add(InterruptedIOException.class);
exceptionBlackList.add(SSLHandshakeException.class);
}
private final int maxRetries;
public RetryHandler(int maxRetries) {
this.maxRetries = maxRetries;
}
@Override
public boolean retryRequest(IOException exception, int retriedTimes, HttpContext context) {
boolean retry = true;
if (exception == null || context == null) {
return false;
}
Object isReqSent = context.getAttribute(ExecutionContext.HTTP_REQ_SENT);
boolean sent = isReqSent == null ? false : (Boolean) isReqSent;
if (retriedTimes > maxRetries) {
retry = false;
} else if (exceptionBlackList.contains(exception.getClass())) {
retry = false;
} else if (exceptionWhiteList.contains(exception.getClass())) {
retry = true;
} else if (!sent) {
retry = true;
}
if (retry) {
try {
Object currRequest = context.getAttribute(ExecutionContext.HTTP_REQUEST);
if (currRequest != null) {
//这里只允许GET请求的重试,因为在一般访问中POST重试会造成重复提交问题,因此不宜使用
if (currRequest instanceof HttpRequestBase) {
HttpRequestBase requestBase = (HttpRequestBase) currRequest;
retry = "GET".equals(requestBase.getMethod());
} else if (currRequest instanceof RequestWrapper) {
RequestWrapper requestWrapper = (RequestWrapper) currRequest;
retry = "GET".equals(requestWrapper.getMethod());
}
} else {
retry = false;
LogUtils.e("retry error, curr request is null");
}
} catch (Throwable e) {
retry = false;
LogUtils.e("retry error", e);
}
}
if (retry) {
SystemClock.sleep(RETRY_SLEEP_INTERVAL); // sleep a while and retry http request again.
}
return retry;
}
}
需要重写SSLSocketFactory来支持所有主机通过
public class DefaultSSLSocketFactory extends SSLSocketFactory {
//ssl上下文环境
private SSLContext sslContext = SSLContext.getInstance("TLS");
//证书保存对象
private static KeyStore trustStore;
static {
try {
trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
//通常这里需要加载证书
trustStore.load(null, null);
} catch (Throwable e) {
e.printStackTrace();
}
}
private static DefaultSSLSocketFactory instance;
public static DefaultSSLSocketFactory getSocketFactory() {
if (instance == null) {
try {
instance = new DefaultSSLSocketFactory();
} catch (Throwable e) {
LogUtils.e(e.getMessage(), e);
}
}
return instance;
}
private DefaultSSLSocketFactory()
throws UnrecoverableKeyException,
NoSuchAlgorithmException,
KeyStoreException,
KeyManagementException {
super(trustStore);
TrustManager trustAllCerts = new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
@Override
public void checkClientTrusted(
java.security.cert.X509Certificate[] chain, String authType)
throws java.security.cert.CertificateException {
}
@Override
public void checkServerTrusted(
java.security.cert.X509Certificate[] chain, String authType)
throws java.security.cert.CertificateException {
}
};
//初始化509凭证信任管理器
sslContext.init(null, new TrustManager[]{trustAllCerts}, null);
//设置所有请求都会得到客户端的信任
this.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
}
@Override
public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException {
//连接SSL Socket
return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
}
@Override
public Socket createSocket() throws IOException {
return sslContext.getSocketFactory().createSocket();
}
}
当然上面的通信谈不上SSL加密,因此使用了https和没使用https请求没啥区别,就像http一样。
对于https安全请求的的加密过程,我们需要充分的认识,简单的说他是一个加密的过程。
对于这个过程的请求才叫安全请求,那么这个请求是怎么构建的呢
一般来说证书放在assets或者raw资源文件下(以下代码来自互联网,用户可以再第一段代码中稍作修改,便可使用)
public void getHttpsKeyStore(){
AssetManager am = context.getAssets();
InputStream ins = am.open("robusoft.cer");
try {
//读取证书
CertificateFactory cerFactory = CertificateFactory.getInstance("X.509"); //问1
Certificate cer = cerFactory.generateCertificate(ins);
//创建一个证书库,并将证书导入证书库
KeyStore keyStore = KeyStore.getInstance("PKCS12", "BC"); //问2
keyStore.load(null, null);
keyStore.setCertificateEntry("trust", cer);
return keyStore;
} finally {
ins.close();
}
}
将这里代码整合到第一段代码中,形成https安全请求,当然也可以单独使用,
public static HttpClient getAndroidHttpClient(int connTimeout, String userAgent,int retryTimes)
{
//......
AssetManager am = context.getAssets();
InputStream ins = am.open("robusoft.cer");
try {
//读取证书
CertificateFactory cerFactory = CertificateFactory.getInstance("X.509"); //问1
Certificate cer = cerFactory.generateCertificate(ins);
//创建一个证书库,并将证书导入证书库
KeyStore keyStore = KeyStore.getInstance("PKCS12", "BC"); //问2
keyStore.load(null, null);
keyStore.setCertificateEntry("trust", cer);
//把咱的证书库作为信任证书库
SSLSocketFactory socketFactory = new SSLSocketFactory(keystore);
schemeRegistry.register(new Scheme("https", socketFactory , 443));
} finally {
ins.close();
}
// ......
}
Android HTTPPost返回错误“方法不允许”
我正在编写一个Android 2.2应用程序,该应用程序将JSON严格性过帐到ReSTfull Web服务。
Fiddler对Web服务的调用具有与预期相同的Json返回,而对ASPX Web应用程序具有与预期的相同Json返回。
当我查看服务器日志时,可以看到服务器使用307重定向响应初始POST动词,然后立即响应GET和405错误。
Fiddler和aspx应用程序记录一个307重定向的POST,然后立即另一个POST和200 OK。
到底是怎么回事?
这是主要活动:
package com.altaver.android_PostJson2;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
public class PostJson extends Activity {
private static final String TAG = "MainActivity";
private static final String URL = "http://web2.altaver.com/sdz/avReSTfulLogin1";
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
JSONObject jsonObjSend = new JSONObject();
try {
jsonObjSend.put("Pass","sz");
jsonObjSend.put("User","szechman");
Log.i(TAG,jsonObjSend.toString(2));
} catch (JSONException e) {
e.printStackTrace();
}
JSONObject jsonObjRecv = HttpClient.SendHttpPost(URL,jsonObjSend);
//examine JSONObject later
}
}
这是进行Web服务调用的类代码:
package com.altaver.android_PostJson2;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.params.HttpClientParams;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONObject;
import android.util.Log;
public class HttpClient {
private static final String TAG = "HttpClient";
public static JSONObject SendHttpPost(String URL,JSONObject jsonObjSend) {
try {
DefaultHttpClient httpclient = new DefaultHttpClient();
HttpClientParams.setRedirecting(httpclient.getParams(),true);
//added cookie policy,wild shot in the dark
//httpclient.getParams().setParameter(ClientPNames.COOKIE_POLICY,>CookiePolicy.RFC_2109);
HttpPost httpPostRequest = new HttpPost(URL);
StringEntity se;
se = new StringEntity(jsonObjSend.toString());
// Set HTTP parameters
httpPostRequest.setEntity(se);
//httpPostRequest.setHeader("User-Agent",>"com.altaver.android_PostJson2");
httpPostRequest.setHeader("User-Agent","Mozilla/5.0 (Windows; U; >Windows NT 5.1; en-US; rv:1.9.2.3) Gecko/20100401");
httpPostRequest.setHeader("Accept","application/json");
httpPostRequest.setHeader("Content-Type","application/json");
long t = System.currentTimeMillis();
HttpResponse response = (HttpResponse) >httpclient.execute(httpPostRequest);
Log.i(TAG,"HTTPResponse received in [" + >(System.currentTimeMillis()-t) + "ms]");
HttpEntity entity = response.getEntity();
if (entity != null) {
InputStream instream = entity.getContent();
Header contentEncoding = response.getFirstHeader("Content-Encoding");
String resultString= convertStreamToString(instream);
instream.close();
resultString = resultString.substring(1,resultString.length()-1); // >remove wrapping "[" and "]"
JSONObject jsonObjRecv = new JSONObject(resultString);
Log.i(TAG,"<jsonobject>\n"+jsonObjRecv.toString()+"\n</jsonobject>");
return jsonObjRecv;
}
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
private static String convertStreamToString(InputStream is) {
/*
* To convert the InputStream to String we use the >BufferedReader.readLine()
* method. We iterate until the BufferedReader return null which means
* there's no more data to read. Each line will appended to a >StringBuilder
* and returned as String.
*
* (c) public domain: http://senior.ceng.metu.edu.tr/2009/praeda/2009/01>/11/a-simple-restful-client-at-android/
*/
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line = null;
try {
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return sb.toString();
}
}
今天关于Android 8:不允许明文 HTTP 流量和安卓11不允许访问data的介绍到此结束,谢谢您的阅读,有关Android 8:不允许使用Cleartext HTTP流量、android httpClient (https/http) 的优化构建方式二、android httpClient(https/http)的优化构建方式一、Android HTTPPost返回错误“方法不允许”等更多相关知识的信息可以在本站进行查询。
本文标签: