「Android/HttpRequest通信/HttpURLConnection」の版間の差分
(→AsyncTask経由) |
(→Causee: java.security.cert.CertificateException: Chain validation failedエラーが出るとき) |
||
(同じ利用者による、間の8版が非表示) | |||
行43: | 行43: | ||
HttpURLConnection urlConn = null; | HttpURLConnection urlConn = null; | ||
HashMap<String,String> mParams = new HashMap<String,String>(); | HashMap<String,String> mParams = new HashMap<String,String>(); | ||
+ | String body = ""; | ||
public void setParams(HashMap<String,String> params) { | public void setParams(HashMap<String,String> params) { | ||
mParams = params; | mParams = params; | ||
行81: | 行82: | ||
} | } | ||
Log.i("HttpURLConnection", "res=" + output.toString()); | Log.i("HttpURLConnection", "res=" + output.toString()); | ||
+ | body = output.toString(); | ||
} | } | ||
} catch (SocketTimeoutException e) { | } catch (SocketTimeoutException e) { | ||
行143: | 行145: | ||
} | } | ||
Log.i("HttpURLConnection", "res=" + output.toString()); | Log.i("HttpURLConnection", "res=" + output.toString()); | ||
+ | body = output.toString(); | ||
} | } | ||
} catch (SocketTimeoutException e) { | } catch (SocketTimeoutException e) { | ||
行160: | 行163: | ||
} | } | ||
} | } | ||
+ | } | ||
+ | public String getBody() { | ||
+ | return body; | ||
} | } | ||
} | } | ||
行287: | 行293: | ||
</pre> | </pre> | ||
+ | ==ThreadRunnable経由== | ||
-MainActivity.java | -MainActivity.java | ||
<pre> | <pre> | ||
行315: | 行322: | ||
}).start(); | }).start(); | ||
</pre> | </pre> | ||
+ | |||
+ | ===android.os.NetworkOnMainThreadExceptionエラーが出る場合=== | ||
+ | UIThreadでネットワークにアクセスするとそうなるので、 | ||
+ | <pre> | ||
+ | HandlerThread thread = new HandlerThread("other"); | ||
+ | thread.start(); | ||
+ | final Handler handler = new Handler(thread.getLooper()); | ||
+ | </pre> | ||
+ | が | ||
+ | Handler handler = new Handler(Looper.getMainLooper()); | ||
+ | になってないか確認する。 | ||
==戻り値を受けたい場合== | ==戻り値を受けたい場合== | ||
行324: | 行342: | ||
https://qiita.com/maromaro3721/items/c9e16068d13e8ca217f5 | https://qiita.com/maromaro3721/items/c9e16068d13e8ca217f5 | ||
+ | |||
+ | ==Causee: java.security.cert.CertificateException: Chain validation failedエラーが出るとき== | ||
+ | 自己署名証明書を通すように。 | ||
+ | 参考:https://www.it-swarm.dev/ja/android/okhttp%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%97%E3%81%A6%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E8%A8%BC%E6%98%8E%E6%9B%B8%E3%82%92%E4%BF%A1%E9%A0%BC%E3%81%99%E3%82%8B/1048177852/ | ||
+ | |||
+ | 以下add分を追加すればよい。 | ||
+ | <pre> | ||
+ | URL url = new URL(url); | ||
+ | urlConn = (HttpsURLConnection) url.openConnection(); | ||
+ | urlConn.setRequestMethod("GET"); | ||
+ | // add start | ||
+ | TrustManager[] trustAllCerts = new TrustManager[] { | ||
+ | new X509TrustManager() { | ||
+ | @Override | ||
+ | public X509Certificate[] getAcceptedIssuers() { | ||
+ | return new X509Certificate[] {}; | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public void checkClientTrusted(X509Certificate[] chain, String authType) | ||
+ | throws CertificateException { | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public void checkServerTrusted(X509Certificate[] chain, String authType) | ||
+ | throws CertificateException { | ||
+ | } | ||
+ | } | ||
+ | }; | ||
+ | SSLContext ctx = SSLContext.getInstance("TLS"); | ||
+ | ctx.init(null, trustAllCerts, new SecureRandom()); | ||
+ | SSLSocketFactory factory = ctx.getSocketFactory(); | ||
+ | urlConn.setSSLSocketFactory(factory); | ||
+ | // add end | ||
+ | urlConn.connect(); | ||
+ | </pre> | ||
+ | |||
+ | ===openStreamで起こる場合=== | ||
+ | 以下のように、urlのopenStrem()を削除してHttpsURLConnectionのgetInputStream()を追加して、上記項目のように、TLSの記述をHttpsURLConnectionへ追加する。 | ||
+ | <pre> | ||
+ | URL url = new URL(url); | ||
+ | - is = url.openStream(); | ||
+ | HttpsURLConnection urlConn = (HttpsURLConnection)u.openConnection(); | ||
+ | + is = urlConn.getInputStream(); | ||
+ | </pre> | ||
+ | |||
+ | ===KitKat(4.4)でSSLのConnection reset by peerエラーが出るとき=== | ||
+ | 以下エラーが出るとき | ||
+ | <pre> | ||
+ | Error Msg: SSL handshake aborted: ssl=0x761439c0: I/O error during system call, Connection reset by peer | ||
+ | </pre> | ||
+ | 以下を入れると直った。 | ||
+ | <pre> | ||
+ | try { | ||
+ | ProviderInstaller.installIfNeeded(mContext.getApplicationContext()); | ||
+ | } catch (GooglePlayServicesRepairableException e) { | ||
+ | e.printStackTrace(); | ||
+ | } catch (GooglePlayServicesNotAvailableException e) { | ||
+ | e.printStackTrace(); | ||
+ | } | ||
+ | </pre> | ||
+ | 参考:https://www.it-swarm.dev/ja/android/javaxnetsslsslexception%EF%BC%9Aandroid%E5%8F%A4%E3%81%84%E3%83%87%E3%83%90%E3%82%A4%E3%82%B9%E3%81%A7ssl%E3%83%8F%E3%83%B3%E3%83%89%E3%82%B7%E3%82%A7%E3%82%A4%E3%82%AF%E3%81%8C%E4%B8%AD%E6%AD%A2%E3%81%95%E3%82%8C%E3%81%BE%E3%81%97%E3%81%9F/829670631/ |
2020年9月4日 (金) 15:23時点における最新版
目次
準備
AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET" />
サンプル
同期処理のみ(AsyncTaskなどで実行すること)
get
CustomHttpURLConnection http = new CustomHttpURLConnection(); HashMap<String, String> params = new HashMap<String, String>(); params.put("errorlog", stackTrace); http.setParams(params); http.execGet("https://api.github.com/feeds");
post
CustomHttpURLConnection http = new CustomHttpURLConnection(); HashMap<String, String> params = new HashMap<String, String>(); params.put("errorlog", stackTrace); http.setParams(params); http.execPost("https://api.github.com/feeds");
CustomHttpURLConnection.java
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintWriter; import java.net.HttpURLConnection; import java.net.SocketTimeoutException; import java.net.URL; import java.util.HashMap; import java.util.Set; import android.net.Uri; import android.util.Log; class CustomHttpURLConnection { HttpURLConnection urlConn = null; HashMap<String,String> mParams = new HashMap<String,String>(); String body = ""; public void setParams(HashMap<String,String> params) { mParams = params; } public void execGet(String strUrl) { // System.setProperty("http.agent", "Dalvik/2.1.0 (Linux; U; Android 9; H8216 Build/PDP-PKQ1.180708.001-10229)"); // System.getProperty("http.agent"); Log.i("HttpURLConnection", "ua=" + System.getProperty("http.agent")); InputStream in = null; BufferedReader reader = null; try { if (mParams.size() > 0) { Uri.Builder builder = new Uri.Builder(); Set keys = mParams.keySet(); for (Object key : keys) { builder.appendQueryParameter((String) key, mParams.get((String) key)); } String join = builder.build().getEncodedQuery(); Log.i("HttpURLConnection", "join=" + join); strUrl = strUrl + "?" + join; } Log.i("HttpURLConnection", "url=" + strUrl); URL url = new URL(strUrl); urlConn = (HttpURLConnection) url.openConnection(); urlConn.addRequestProperty("Content-Type", "application/json; charset=UTF-8"); urlConn.setRequestMethod("GET"); urlConn.setConnectTimeout(10000); // 10s urlConn.setReadTimeout(1000); // 1s urlConn.connect(); int status = urlConn.getResponseCode(); Log.i("HttpURLConnection", "status_code=" + status); if (status == HttpURLConnection.HTTP_OK) { in = urlConn.getInputStream(); reader = new BufferedReader(new InputStreamReader(in)); StringBuilder output = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { output.append(line); } Log.i("HttpURLConnection", "res=" + output.toString()); body = output.toString(); } } catch (SocketTimeoutException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { if (reader != null) { reader.close(); } if (urlConn != null) { urlConn.disconnect(); } } catch (IOException e) { e.printStackTrace(); } } } public void execPost(String strUrl) { // System.setProperty("http.agent", "Dalvik/2.1.0 (Linux; U; Android 9; H8216 Build/PDP-PKQ1.180708.001-10229)"); // System.getProperty("http.agent"); Log.i("HttpURLConnection", "ua=" + System.getProperty("http.agent")); HttpURLConnection urlConn = null; InputStream in = null; BufferedReader reader = null; try { URL url = new URL(strUrl); urlConn = (HttpURLConnection) url.openConnection(); urlConn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); urlConn.setRequestMethod("POST"); urlConn.setConnectTimeout(10000); // 10s urlConn.setReadTimeout(1000); // 1s urlConn.setInstanceFollowRedirects(false); urlConn.setRequestProperty("Accept-Language", "jp"); urlConn.setDoOutput(true); OutputStream outputStream = urlConn.getOutputStream(); Log.i("HttpURLConnection", "mParams.size()=" + mParams.size()); if (mParams.size() > 0) { Uri.Builder builder = new Uri.Builder(); Set keys = mParams.keySet(); for (Object key : keys) { builder.appendQueryParameter((String) key, mParams.get((String) key)); } String join = builder.build().getEncodedQuery(); Log.i("HttpURLConnection", "join=" + join); PrintWriter ps = new PrintWriter(outputStream); ps.print(join); ps.close(); } outputStream.close(); int status = urlConn.getResponseCode(); String resmessage = urlConn.getResponseMessage(); Log.i("HttpURLConnection", "status_code=" + status); Log.i("HttpURLConnection", "message=" + resmessage); if (status == HttpURLConnection.HTTP_OK) { in = urlConn.getInputStream(); reader = new BufferedReader(new InputStreamReader(in)); StringBuilder output = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { output.append(line); } Log.i("HttpURLConnection", "res=" + output.toString()); body = output.toString(); } } catch (SocketTimeoutException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { if (reader != null) { reader.close(); } if (urlConn != null) { urlConn.disconnect(); } } catch (IOException e) { e.printStackTrace(); } } } public String getBody() { return body; } }
urlConn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); はjsonでなくpost時はこんな感じにしないとならない。
uaはサーバに接続して変更設定されていることを確認済み。
ドメイン接続許可しないエラーが出るときはこちらを確認
android/開発環境/Android8 [ショートカット]
参考
https://itsakura.com/java-httpurlconnection
http://d.hatena.ne.jp/Kazuhira/20131026/1382796711
uaを設定しない場合とwebviewからもてっくる場合
HttpURLConnectionのuaデフォ(System.getProperty("http.agent");)
Dalvik/2.1.0 (Linux; U; Android 9; Pixel 2 XL Build/PPR2.181005.003)
webviewのua android/webview/useragent [ショートカット]
Mozilla/5.0 (Linux; Android 9; Pixel 2 XL Build/PPR2.181005.003; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/70.0.3538.110 Mobile Safari/537.36
retry処理
本来のget処理をexecGetCore()に入れる
public boolean execGet() throws Exception { Exception tmpException = null; for (int retry = 0; retry <= mRetry; retry++) { try { boolean ret = execGetCore(); if (ret) { return ret; } } catch (Exception e) { tmpException = e; } } if (Exception != null) { throw tmpException; } return false; }
AsyncTask経由
import android.app.Activity; import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnCancelListener; import android.os.AsyncTask; import android.util.Log; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; /* HttpAsyncTask task = new HttpAsyncTask(); task.setParam1("hoge"); task.execute(); */ public class HttpAsyncTask extends AsyncTask<String, Integer, Long> implements OnCancelListener { private final String TAG = "MyAsyncTask"; private Context mContext; private Activity mActivity; private String param1; public HttpAsyncTask(Context context) { this.mContext = context; } public void setActivity(Activity activity) { mActivity = activity; } public void setParam1(String str) { this.param1 = str; } @Override protected void onPreExecute() { Log.d(TAG, "onPreExecute"); } @Override protected Long doInBackground(String... urls) { CustomHttpURLConnection http = new CustomHttpURLConnection(); try { String encode = URLEncoder.encode(param1, "UTF-8"); String url = "ttps://hoge.example.com/hoge?param1=" + encode; http.execGet(url); Log.d(TAG, url); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return 123L; } @Override protected void onProgressUpdate(Integer... values) { Log.d(TAG, "onProgressUpdate=" + values[0]); } @Override protected void onCancelled() { Log.d(TAG, "onCancelled"); } @Override protected void onPostExecute(Long result) { Log.d(TAG, "onPostExecute=" + result); } public void onCancel(DialogInterface dialog) { Log.d(TAG, "Dialog onCancell... calling cancel(true)"); this.cancel(true); } }
-MainActivity.java
HttpAsyncTask task = new HttpAsyncTask(); task.setParam1("hoge"); task.execute(); try { task.get(); // awaitのように待機待ちする場合はget()で待機待できる } catch (ExecutionException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); }
ThreadRunnable経由
-MainActivity.java
HandlerThread thread = new HandlerThread("other"); thread.start(); final Handler handler = new Handler(thread.getLooper()); new Thread(new Runnable() { @Override public void run() { if (handler != null) { handler.post(new Runnable() { @Override public void run() { CustomHttpURLConnection http = new CustomHttpURLConnection(); try { String encode = URLEncoder.encode(param1, "UTF-8"); String url = "ttps://example.com/hoge?param1=" + encode; http.execGet(url); Log.i("test", http.getBody()); Log.d("test", url); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } }); } } }).start();
android.os.NetworkOnMainThreadExceptionエラーが出る場合
UIThreadでネットワークにアクセスするとそうなるので、
HandlerThread thread = new HandlerThread("other"); thread.start(); final Handler handler = new Handler(thread.getLooper());
が
Handler handler = new Handler(Looper.getMainLooper());
になってないか確認する。
戻り値を受けたい場合
Listenerを使うとか、CountDownLatchを使うとか。
CountDownLatchの参考
https://docs.oracle.com/javase/jp/8/docs/api/java/util/concurrent/CountDownLatch.html
https://qiita.com/maromaro3721/items/c9e16068d13e8ca217f5
Causee: java.security.cert.CertificateException: Chain validation failedエラーが出るとき
以下add分を追加すればよい。
URL url = new URL(url); urlConn = (HttpsURLConnection) url.openConnection(); urlConn.setRequestMethod("GET"); // add start TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() { @Override public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[] {}; } @Override public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } @Override public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { } } }; SSLContext ctx = SSLContext.getInstance("TLS"); ctx.init(null, trustAllCerts, new SecureRandom()); SSLSocketFactory factory = ctx.getSocketFactory(); urlConn.setSSLSocketFactory(factory); // add end urlConn.connect();
openStreamで起こる場合
以下のように、urlのopenStrem()を削除してHttpsURLConnectionのgetInputStream()を追加して、上記項目のように、TLSの記述をHttpsURLConnectionへ追加する。
URL url = new URL(url); - is = url.openStream(); HttpsURLConnection urlConn = (HttpsURLConnection)u.openConnection(); + is = urlConn.getInputStream();
KitKat(4.4)でSSLのConnection reset by peerエラーが出るとき
以下エラーが出るとき
Error Msg: SSL handshake aborted: ssl=0x761439c0: I/O error during system call, Connection reset by peer
以下を入れると直った。
try { ProviderInstaller.installIfNeeded(mContext.getApplicationContext()); } catch (GooglePlayServicesRepairableException e) { e.printStackTrace(); } catch (GooglePlayServicesNotAvailableException e) { e.printStackTrace(); }