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();
}
}