Android中的HTTP通信筆記(慕課網)
本文是基於慕課網nate老師講解Android中Http通信,自己做的整理筆記,在此感謝nate老師和慕課網的分享,視頻鏈接如下http://www.imooc.com/learn/304
HTTP協議
HTTP協議是超文本傳輸協議定義了瀏覽器怎麼向萬維網請求萬維網文檔,及服務器怎麼把文檔傳送給瀏覽器。從層次的角度看,HTTP協議是面向應用層的協議。
HTTP協議特點
HTTP協議特點包括以下幾個方面:
支持客戶機服務器模式
簡單快速:客戶機向服務器請求服務時,只需要傳送請求方法和路徑。請求的方法包括GET、HEAD、POST等。每種方法規定了客戶與服務器聯繫的類型不同。由於HTTP協議簡單,使得HTTP服務器的規模小,通信速度快。
靈活:HTTP運行傳輸任何類型的數據對象。
無連接:限制每次連接只處理一個請求。服務器處理完用戶的請求,並收到客戶的應答後,即斷開連接。採用這種方式可以節省傳輸時間。
無狀態:HTTP協議是無狀態協議。無狀態是指協議對於事務的處理沒有記憶的能力。缺少狀態意味着如果後續處理需要前面的信息,則必須重傳,這樣可能導致每次連接傳送的數據量增大。另一方面,在服務器不需要先前信息時它的應答就較快。
一個HTTP協議操作成爲一個事務,其工作過程可以分爲四步:
首先客戶機和服務器之間建立相應的連接,只要單擊某個超鏈接,HTTP就可以工作。
建立連接之後,客戶機發送一個請求給服務器,請求方式的格式爲:統一資源標識符(URL)、協議版本號,後邊的MIME信息包括請求標識符、客戶機信息和可能的內容。
服務器接收到請求後 ,給予相應的相應信息。其格式爲一個狀態行,包括信息的協議版本號、一個成功或錯誤的代碼,後邊是MIME信息包括服務器信息、實體信息和可能的內容。
客戶端接收服務器所返回的信息通過瀏覽器顯示在用戶的現實屏上,然後客戶機與服務器斷開連接。
統一資源定位符(URL)
統一資源定位符(URL)也被稱爲網頁地址。
URL的格式由三部分組成:
第一部分是協議;
第二部分是存有該資源的主機IP地址(有時也包括端口號);
第三部分是主機資源的具體地址。
eg.http//www.imooc.com/index.jsp
TCP三次握手
SYN是TCP/IP建立連接時使用的握手信號。客戶機和服務器之間建立連接,首先客戶機發出一個SYN信號,服務器使用SYN+ACK應答表示接收到了這個消息,最後客戶機再以ACK消息響應。
ACK即確認符,在數據通信中,接收站給發送站的一種傳輸類控制字符,表示發來的數據已確認接收無誤。
HTTP請求
Http請求由三部分組成,分別是:請求行、消息報頭、請求正文。
請求行以一個方法符號開頭,以空格分開,後面跟着請求的URI和協議的版本號,格式如下:Method Request-URI HTTP-Version CRLF
其中Method表示請求的方法;Request-URI是一個統一資源標識符;HTTP-Version標識請求的HTTP協議版本;CRLF表示回車和換行(除了作爲結尾的CRLF之外,不允許出現單獨的CR或LF字符)。
請求方法(所有方法全爲大寫)有多種,各個方法解釋如下:
GET 請求獲取Request-URI所標識的資源
POST 在Request-URI所標識的資源後附加新的數據
HEAD 請求獲取由Request-URI所標識的資源的響應消息報頭
PUT 請求服務器存儲一個資源,並用Request-URI作爲其標識
DELETE 請求服務器刪除Request-URI所標識的資源
TRACE 請求服務器回送收到的請求信息,主要用於測試或診斷
CONNECT 保留將來使用
OPTIONS 請求查詢服務器的性能,或者查詢與資源相關的選項和需求
應用舉例:
GET方法:在瀏覽器的地址欄輸入網址的方式訪問網頁時,瀏覽器採用GET方法向服務器獲取資源,eg:GET/form.html HTTP/1.1(CRLF)
POST方法:要求被請求服務器接受負載請求後面的數據,常用於提交表單。
HTTP響應
在接收和解釋請求消息後,服務器返回一個HTTP響應消息。
HTTP響應也是由三個部分組成,分別是:狀態行、消息報頭、響應正文。
狀態行格式如下:
HTTP-Version Status——Code Reason-Phrase CRLF
其中,HTTP-Version標識服務器HTTP協議的版本;Status-Code標識服務器發回的響應狀態代碼;Reason-Phrase表示狀態代碼的文本描述。
狀態代碼有三位數字組成,第一個數字定義了響應的類別,且有五種可能取值:
1xx:指示信息–表示請求已接收,繼續處理
2xx:成功–表示請求已被成功接收、理解、接受
3xx:重定向–要完成請求必須進行更進一步的操作
4xx:客戶端錯誤–請求有語法錯誤或請求無法實現
5xx:服務器端錯誤–服務器未能實現合法的請求
常見狀態代碼、狀態描述、說明:
200 OK //客戶端請求成功
400 Bad Request //客戶端請求有語法錯誤,不能被服務器所理解
401 Unauthorized //請求未經授權,這個狀態代碼必須和WWW-Authenticate報頭域一起使用
403 Forbidden //服務器收到請求,但是拒絕提供服務
404 Not Found //請求資源不存在,eg:輸入了錯誤的URL
500 Internal Server Error //服務器發生不可預期的錯誤
503 Server Unavailable //服務器當前不能處理客戶端的請求,一段時間後可能恢復正常
eg:HTTP/1.1 200 OK (CRLF)
HTTP1.0和HTTP1.1區別
HTTP/1.0 每次請求都需要建立新的TCP連接,連接不可複用。
HTTP/1.1 新的請求可以在上次請求建立的TCP連接之上發送,連接可以複用,優點是減少重複進行TCP三次握手的開銷,提高效率。
HTTP/1.1 在Request消息頭裏多了一個HOST域,HTTP1.0則沒有這個域。HOST:www.w3.org
HTTP1.1 增加了OPTIONS,PUT,DELETE,TRACE,CONNECT這些Request方法。
HttpURLConnection
在Android中發送HTTP請求的方式一般有兩種,HttpURLConnection和HttpClient(Android 5.0中已棄用)在這裏我們只介紹HttpURLConnection.
從網上下載圖片保存到SD中
- 代碼
HttpThread.java
package com.excavator.http_01;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;
import android.os.Handler;
import android.webkit.WebView;
import android.widget.ImageView;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
/**
* Created by admin on 2015/4/16.
*/
public class HttpThread extends Thread {
private String url;
private WebView webView;
private Handler handler;
private ImageView imageView;
public HttpThread(String url, WebView webView, Handler handler) {
this.url = url;
this.webView = webView;
this.handler = handler;
}
public HttpThread(String url, ImageView imageView,Handler handler) {
this.url = url;
this.handler = handler;
this.imageView = imageView;
}
@Override
public void run() {
try {
URL httpUrl = new URL(url);
try {
//從Url建立Http連接
HttpURLConnection connection = (HttpURLConnection) httpUrl.openConnection();
connection.setReadTimeout(5000);
connection.setRequestMethod("GET");
connection.setDoInput(true);
//從Http連接獲取輸入流
InputStream in = connection.getInputStream();
FileOutputStream outputStream=null;
File downloadFile=null;
String fileName = String.valueOf(System.currentTimeMillis());
//判斷外部SD卡是否存在
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
File parent = Environment.getExternalStorageDirectory(); //獲取SD卡根目錄
downloadFile=new File(parent,fileName); //在SD卡根目錄下新建downloadFile
outputStream0.000000000000000000 = new FileOutputStream(downloadFile); //構建寫字節到downloadFile的輸出流
}
//建立緩衝數組
byte[] b = new byte[2*1024];
int len;
if (outputStream!=null){
while ((len=in.read(b))!=-1){ //讀輸入流中的字符緩衝到字節數組b中
outputStream.write(b,0,len);//寫字節數組b中的字符到輸出流中(即到文件downloadFile中)
}
}
//解碼文件路徑爲位圖bitmap
final Bitmap bitmap = BitmapFactory.decodeFile(downloadFile.getAbsolutePath());
handler.post(new Runnable() {
@Override
public void run() {
imageView.setImageBitmap(bitmap);
}
});
/*final StringBuffer stringBuffer = new StringBuffer();
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String str;
while ((str=reader.readLine())!=null) {
stringBuffer.append(str);
}
handler.post(new Runnable() {
@Override
public void run() {
webView.loadData(stringBuffer.toString(), "text/html;charset=utf-8", null);
}
});*/
} catch (IOException e) {
e.printStackTrace();
}
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
}
MainActivity.java
package com.excavator.http_01;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.ActionBarActivity;
import android.webkit.WebView;
import android.widget.ImageView;
public class MainActivity extends ActionBarActivity {
private WebView webView;
private Handler handler=new Handler();
private ImageView imageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//webView = (WebView) findViewById(R.id.webView);
imageView = (ImageView) findViewById(R.id.imageView);
new HttpThread("http://h.hiphotos.baidu.com/image/pic/item/6c224f4a20a446239e8d311c9b22720e0cf3d70d.jpg",imageView,handler).start();
}
}
GET、POST傳遞參數
主機服務器代碼
MyServlet.java
package com.imooc.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class MyServlet
*/
@WebServlet("/MyServlet")
public class MyServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public MyServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
this.doPost(request, response);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
String name=request.getParameter("name");
String age=request.getParameter("age");
response.setContentType("text/html;charset=utf-8");
PrintWriter out=response.getWriter();
//out.println("name="+new String(name.getBytes("iso-8859-1"),"utf-8")+"age="+age);
out.println("name="+name+"age="+age);
//System.out.println("name="+new String(name.getBytes("iso-8859-1"),"utf-8"));
System.out.println("name="+name);
System.out.println("age="+age);
}
}
HttpThread1(從Android端向服務器端提交數據)
package com.excavator.http_01;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Properties;
/**
* Created by admin on 2015/4/17.
*/
public class HttpThread1 extends Thread {
String url;
String name;
String age;
public HttpThread1(String url, String name, String age) {
this.url = url;
this.name = name;
this.age = age;
}
private void doGet() {
try {
url = url + "?name=" + URLEncoder.encode(name,"utf-8") + "&age=" + age; //此處URLEncoder中的encode方法用於轉碼,因爲Android中編碼是utf-8碼,若不轉碼,服務器端接收到中文會是亂碼。
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
try {
URL httpUrl = new URL(url);
try {
HttpURLConnection httpURLConnection = (HttpURLConnection) httpUrl.openConnection();
httpURLConnection.setRequestMethod("GET");
httpURLConnection.setReadTimeout(5000);
BufferedReader reader = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream()));
String str;
StringBuffer stringBuffer = new StringBuffer();
while ((str = reader.readLine()) != null) {
stringBuffer.append(str);
}
System.out.println("result" + stringBuffer.toString());
} catch (IOException e) {
e.printStackTrace();
}
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
private void doPost() {
try {
Properties properties = System.getProperties();
properties.list(System.out);
URL httpUrl = new URL(url);
try {
HttpURLConnection httpURLConnection = (HttpURLConnection) httpUrl.openConnection();
httpURLConnection.setRequestMethod("POST");
httpURLConnection.setReadTimeout(5000);
OutputStream out = httpURLConnection.getOutputStream();
String content = "name=" + name + "&age=" + age;
out.write(content.getBytes());
BufferedReader reader = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream()));
StringBuffer sb = new StringBuffer();
String str;
while ((str = reader.readLine()) != null) {
sb.append(str);
}
System.out.println(sb.toString());
} catch (IOException e) {
e.printStackTrace();
}
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
@Override
public void run() {
super.run();
doGet();
// doPost();
}
}