Android HTTPリクエストメソッド: HttpURLConnection
このセクションの紹介:
前の 2 つのセクションでは、HTTP プロトコルとプロトコル ヘッダーのいくつかの概念について説明しましたが、このセクションでは コードを積み上げていきます。このセクションでは、Android が提供する Http リクエスト メソッドの 1 つである HttpURLConnection について説明します。 これに加えて、別の種類の HttpClient があります。これについては次のセクションで説明します。ただし、リクエストが複雑になった場合は前者を使用できます。 これは非常に面倒で、後者は Java パケット キャプチャでよく使用されます。結局のところ、これは Google の息子ではなく、バージョン 4.4 からのものです。 HttpURLConnection は OkHttp! に置き換えられました。さて、時代の流れに合わせて、HttpClient の話をした後でこの話をすることにしました。 わかりました!ちなみに、実際の開発ではHttpURLConnectionとHttpClientは一般的には使用せず、他のものを使ってカプセル化します。 ネットワーク操作には Volley、android-async-http、loopj などの優れたサードパーティ ネットワーク リクエスト フレームワークが必要です。 非同期やマルチスレッドは自分でやると非常に面倒なので、実際の開発はサードパーティを直接使うべきです! !もちろん私も勉強します 結局のところ、サードパーティもこれらの基盤に基づいて構築されており、高品質のアーキテクチャとさまざまな最適化が施されているため、問題ありません。さて、早速始めましょう このセクションの内容!
1. HttpURLConnection の概要
回答: HTTP 操作に使用でき、ほとんどのアプリケーションに適した多目的の軽量 HTTP クライアントです。 HttpURLConnection が提供する API は比較的シンプルですが、これにより使いやすくなります。 使って拡張してください。抽象クラスである URLConnection を継承し、オブジェクトを直接インスタンス化することはできません。 openCollection() を呼び出すことにより このメソッドは、デフォルトで gzip で圧縮されたオブジェクト インスタンスを取得します。
2. HttpURLConnection を使用する手順は次のとおりです。
- URL オブジェクトを作成します: URL url = 新しい URL(http://www.baidu.com);
- URL オブジェクトの openConnection() を呼び出して HttpURLConnection オブジェクト インスタンスを取得します: HttpURLConnection conn = (HttpURLConnection ) url .openConnection();
- HTTP リクエストに使用されるメソッドを設定します: GET または POST、またはその他のリクエスト メソッド: PUTconn.setRequestMethod("GET");
- 接続タイムアウトを設定し、タイムアウトのミリ秒数、およびサーバーが取得を希望するいくつかのメッセージ ヘッダーconn.setConnectTimeout(6*1000);conn.setReadTimeout(6 * 1000);
- getInputStream() メソッドを呼び出して、サーバーから返された入力ストリームを読み取り、入力ストリームを読み取りますInputStream in = conn.getInputStream();
- 最後に、disconnect() メソッドを呼び出して HTTP 接続をオフにしますconn.disconnect();
追記: 上記に加えて、200 などのレスポンスコードを判断する必要がある場合もあります。 if(conn.getResponseCode() != 200) といくつかの処理を行うこともあります。 パラメータを渡す必要はありませんが、ページに直接アクセスするには、次のものを直接使用できます。 最終的な入力ストリーム = 新しい URL("url").openStream(); 次にストリームを直接読み取りますが、このメソッドは実際にはページへの直接アクセスに適しています。 openConnection().getInputStream() を返しますが、まだいくつかを設定できません あくまで要望なので、こう書きたいかどうかは自分で判断してください!
3.HttpURLConnection の使用例
ここでは主に GET リクエストと POST リクエストの 2 つの異なる使用例を書きます。conn.getInputStream() を実行できます。 取得されるのはストリームなので、ストリームをバイナリ配列に変換するクラスを記述する必要があります。ツール クラスは次のとおりです:
StreamTool.java:
/** * Created by Jay on 2015/9/7 0007. */ public class StreamTool { //从流中读取数据 public static byte[] read(InputStream inStream) throws Exception{ ByteArrayOutputStream outStream = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len = 0; while((len = inStream.read(buffer)) != -1) { outStream.write(buffer,0,len); } inStream.close(); return outStream.toByteArray(); } }
これで、例を使って遊んでみましょう。
1) HttpURLConnection が GET リクエストを送信するコード例
レンダリングの実行:
コア部分コード:
レイアウト: activity_main.xml
データクラスの取得: GetData.java :
/** * Created by Jay on 2015/9/7 0007. */ public class GetData { // 定义一个获取网络图片数据的方法: public static byte[] getImage(String path) throws Exception { URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); // 设置连接超时为5秒 conn.setConnectTimeout(5000); // 设置请求类型为Get类型 conn.setRequestMethod("GET"); // 判断请求Url是否成功 if (conn.getResponseCode() != 200) { throw new RuntimeException("请求url失败"); } InputStream inStream = conn.getInputStream(); byte[] bt = StreamTool.read(inStream); inStream.close(); return bt; } // 获取网页的html源代码 public static String getHtml(String path) throws Exception { URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setConnectTimeout(5000); conn.setRequestMethod("GET"); if (conn.getResponseCode() == 200) { InputStream in = conn.getInputStream(); byte[] data = StreamTool.read(in); String html = new String(data, "UTF-8"); return html; } return null; } }
MainActivity.java:
public class MainActivity extends AppCompatActivity { private TextView txtMenu, txtshow; private ImageView imgPic; private WebView webView; private ScrollView scroll; private Bitmap bitmap; private String detail = ""; private boolean flag = false; private final static String PIC_URL = "http://ww2.sinaimg.cn/large/7a8aed7bgw1evshgr5z3oj20hs0qo0vq.jpg"; private final static String HTML_URL = "http://www.baidu.com"; // 用于刷新界面 private Handler handler = new Handler() { public void handleMessage(android.os.Message msg) { switch (msg.what) { case 0x001: hideAllWidget(); imgPic.setVisibility(View.VISIBLE); imgPic.setImageBitmap(bitmap); Toast.makeText(MainActivity.this, "图片加载完毕", Toast.LENGTH_SHORT).show(); break; case 0x002: hideAllWidget(); scroll.setVisibility(View.VISIBLE); txtshow.setText(detail); Toast.makeText(MainActivity.this, "HTML代码加载完毕", Toast.LENGTH_SHORT).show(); break; case 0x003: hideAllWidget(); webView.setVisibility(View.VISIBLE); webView.loadDataWithBaseURL("", detail, "text/html", "UTF-8", ""); Toast.makeText(MainActivity.this, "网页加载完毕", Toast.LENGTH_SHORT).show(); break; default: break; } } ; }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); setViews(); } private void setViews() { txtMenu = (TextView) findViewById(R.id.txtMenu); txtshow = (TextView) findViewById(R.id.txtshow); imgPic = (ImageView) findViewById(R.id.imgPic); webView = (WebView) findViewById(R.id.webView); scroll = (ScrollView) findViewById(R.id.scroll); registerForContextMenu(txtMenu); } // 定义一个隐藏所有控件的方法: private void hideAllWidget() { imgPic.setVisibility(View.GONE); scroll.setVisibility(View.GONE); webView.setVisibility(View.GONE); } @Override // 重写上下文菜单的创建方法 public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { MenuInflater inflator = new MenuInflater(this); inflator.inflate(R.menu.menus, menu); super.onCreateContextMenu(menu, v, menuInfo); } // 上下文菜单被点击是触发该方法 @Override public boolean onContextItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.one: new Thread() { public void run() { try { byte[] data = GetData.getImage(PIC_URL); bitmap = BitmapFactory.decodeByteArray(data, 0, data.length); } catch (Exception e) { e.printStackTrace(); } handler.sendEmptyMessage(0x001); } ; }.start(); break; case R.id.two: new Thread() { public void run() { try { detail = GetData.getHtml(HTML_URL); } catch (Exception e) { e.printStackTrace(); } handler.sendEmptyMessage(0x002); }; }.start(); break; case R.id.three: if (detail.equals("")) { Toast.makeText(MainActivity.this, "先请求HTML先嘛~", Toast.LENGTH_SHORT).show(); } else { handler.sendEmptyMessage(0x003); } break; } return true; } }
最後にネットワーク権限を追加することを忘れないでください:
Notes:
ハンドラーを使用する理由は説明する必要はありません~ さらに、HTML コードをロードするときは、LoadData の代わりに webView のloadDataWithBaseURL を使用します。 LoadDataを使うと中国語の文字化けの問題が気になるので…loadDataWithBaseURLを使えばそこまで気にしなくて済みます。 さらに、一部のページでは、アカウントやパスワードなどのパラメータの送信が必要な場合があります。次のように、対応するパラメータを URL の末尾に接続するだけで済みます。 http://192.168.191.1:8080/CommentServer/LoginServlet?passwd=123&name=Jack 次に、サーバー側の getParamater("passwd") が対応するパラメーターを取得できるようになります。これらは、リクエスト時に明確に表示されます。 したがって、GET メソッドは安全ではありません。もう 1 つの注意点は、Android では 4.0 以降、非 UI スレッドでの UI 操作が許可されていないことです。
2) HttpURLConnection が POST リクエストを送信するコード例
openConnection を通じて取得する GET と POST があります。 HttpURLConnection は、デフォルトで Get リクエストを実行します。 したがって、POST を使用してデータを送信する場合は、事前に関連するパラメーターを設定する必要があります。 conn.setRequestMethod("POST"); conn.setDoOutput(true); conn.setDoInput(true); もあります。 また: conn.setUseCaches(false); POST メソッドはキャッシュできないため、手動で false に設定する必要があります。 特定の実装のコードを参照してください:
Running renderings:
Core code:
PostUtils.java
public class PostUtils { public static String LOGIN_URL = "http://172.16.2.54:8080/HttpTest/ServletForPost"; public static String LoginByPost(String number,String passwd) { String msg = ""; try{ HttpURLConnection conn = (HttpURLConnection) new URL(LOGIN_URL).openConnection(); //设置请求方式,请求超时信息 conn.setRequestMethod("POST"); conn.setReadTimeout(5000); conn.setConnectTimeout(5000); //设置运行输入,输出: conn.setDoOutput(true); conn.setDoInput(true); //Post方式不能缓存,需手动设置为false conn.setUseCaches(false); //我们请求的数据: String data = "passwd="+ URLEncoder.encode(passwd, "UTF-8")+ "&number="+ URLEncoder.encode(number, "UTF-8"); //这里可以写一些请求头的东东... //获取输出流 OutputStream out = conn.getOutputStream(); out.write(data.getBytes()); out.flush(); if (conn.getResponseCode() == 200) { // 获取响应的输入流对象 InputStream is = conn.getInputStream(); // 创建字节输出流对象 ByteArrayOutputStream message = new ByteArrayOutputStream(); // 定义读取的长度 int len = 0; // 定义缓冲区 byte buffer[] = new byte[1024]; // 按照缓冲区的大小,循环读取 while ((len = is.read(buffer)) != -1) { // 根据读取的长度写入到os对象中 message.write(buffer, 0, len); } // 释放资源 is.close(); message.close(); // 返回字符串 msg = new String(message.toByteArray()); return msg; } }catch(Exception e){e.printStackTrace();} return msg; } }
PS: MyEclipse はコンピューターにインストールされておらず、時間の制約があるため、デモは別に書きません。前の Eclipse デモを使用してください。 実際、コアコードを直接見るだけで十分です~ コードのダウンロード: HttpURLConnection example.zip
4. Cookie の問題の処理
これについて説明する前に、まず 2 つの概念を理解する必要があります: Session と CookieCookie はセッション メカニズムの一般的な形式にすぎません。他のメソッドをクライアントの一意の識別子として使用できます。 これはサーバーによって決定され、それを証明できる唯一のものはクライアント ID です。この方法に加えて、URL 書き換えを使用することもできます。 やり方もいろいろ!したがって、今後他の人に「セッションは単なるクッキーではない」などと愚かに言わないでください。
以下は、この Cookie を理解するのに役立つ例です。 Xiaozhu さんはアカウントとパスワードを入力して学校の教育システムにログインし、授業スケジュール情報にアクセスすることに成功しました。 Chrome を使用している場合は、F12 を押して開発モードに入ります。リソース インターフェイスに移動すると、Cookie が表示されます。 Cookie が存在する場所 (ドメイン)。 Cookie が配置されているディレクトリ (パス) Asp.net のデフォルトは、ルート ディレクトリです。Cookie のサイズ:
要求ヘッダーに Cookie フィールドがあることがわかります。
それでは、Cookie をクリアして (または数分待って)、次のリンクにアクセスしてください:
この時点で、ページは自動的にログイン ページに戻ります。もちろん、他の Web サイトによっては、次のようなダイアログ ボックスが表示される場合もあります。 「ログインタイムアウト」のようなものです。
HTTP リクエスト ログインの簡単なプロセスを要約します。 通常、ログイン時、サーバーは Set-Cookie 応答ヘッダーを通じて Cookie を返し、ブラウザーはデフォルトでこの Cookie を保存します。 この Cookie は、後で関連するページにアクセスするときにもたらされます。Cookie がない場合、または Cookie リクエスト ヘッダーを通じて訪問が完了します。 Cookie の有効期限が切れると、ユーザーはログインしていません、ログインがタイムアウトしました、アクセスするにはログインなどの情報が必要であるというメッセージが表示されます。
そして、HttpClient と HttpURLConnection を使用するとき、実際にこのプロセスをシミュレートし、ログイン後に Cookie を取得します。 それを取得してリクエストを送信します。 キーコードは以下の通りです: Cookieの取得: conn.getHeaderField("Set-Cookie"); リクエスト時にCookieを持ち込む: conn.setRequestProperty("Cookie", cookie);
さらに設定リクエストヘッダー この方法に加えて、別の妥協方法を使用することもできます: URL 書き換え: 元のリクエスト リンクに基づいて、...&sessionid=xxxxx のようなパラメータが追加され、サーバーはそれを解析します。 裁判官!
ここでは JSON 文字列の形式を使用します。リクエストを受信すると、サーバーはセッション内のコンテンツを取り出してクエリを作成します~
5. HttpURLConnection を使用して PUT リクエストを送信します
結局のところ、私たちが通常最もよく遭遇する状況は GET と POST です。 Xiaozhu は最初それを知りませんでしたが、後でそれが実際には POST に似ており、POST に基づいて変更するだけでよいことがわかりました。 何かを注文するだけで準備完了です。また、HttpClient は HttpPut API も提供します。 以下は Xiaozhu 自身のプロジェクトで書かれたリクエスト コードです:
public static String LoginByPut(Context mContext, String mobile, String password, int from, String devid,String version_name, int remember_me) { String resp = ""; try { HttpURLConnection conn = (HttpURLConnection) new URL(LOGIN_URL).openConnection(); conn.setRequestMethod("PUT"); conn.setReadTimeout(5000); conn.setConnectTimeout(5000); conn.setDoOutput(true); conn.setDoInput(true); conn.setUseCaches(false); String data = "mobile=" + mobile + "&password=" + password + "&from=" + from + "&devid=" + "devid" + "&version_name=" + "version_name" + "&remember_me=" + remember_me; ; // 获取输出流: OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream()); writer.write(data); writer.flush(); writer.close(); // 获取相应流对象: InputStream in = conn.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(in)); StringBuilder response = new StringBuilder(); String line; while ((line = reader.readLine()) != null) response.append(line); SPUtils.put(mContext, "session", conn.getHeaderField("Set-Cookie")); // 资源释放: in.close(); // 返回字符串 Log.e("HEHE", response.toString()); return response.toString(); } catch (Exception e) { e.printStackTrace(); } return ""; }
このセクションの概要:
さて、このセクションの HttpUrlConnection の使用方法の紹介はここで終わります。また、HTTP セクションのほとんどは Xiaozhu pig からのものです。 以前に書いた小さなコレクション Android 用 Http Communication このシリーズを読んでいる場合は、このセクションのほとんどを読み飛ばしてください。 同じ!それでは、以上です、ありがとうございます~