HTTP网络请求
对于android开发来说,http是网络开发中最为重要、使用频率最高的手段。
HTTP请求原理
http是一种应用层协议,它通过tcp实现了可靠的数据传输。详细的交互流程如下:
- 客户端执行网络请求,从url中解析出服务器的主机名
- 将服务器的主机名转换成服务器ip地址
- 将端口号从url中解析出来
- 建立一条客户端与服务器的tcp链接
- 客户端通过输入流向服务器发送一条http请求
- 服务器向客户端回送一条http响应报文
- 客户端从输入流获取报文
- 解析报文,关闭连接
HTTP请求方式
- get请求(查)
- post请求(改)
- delete请求(删)
- put请求(增)
- head请求:服务器只返回首部,不会返回实体的主体部分。
- trace请求:客户端发起一个请求,可能需要通过防火墙、代理、网关或其他一些应用程序。每个节点都可能修改原始的请求。trace请求会有目的服务器发起一个环回诊断,行程最后一站的服务器会弹回一条trace响应,并在响应主体中携带它收到的原始请求报文。
- options请求:请求web服务器告知其支持的各种功能。
HTTP报文格式解析
请求报文
通常来说HTTP请求报文由请求行(request line)、请求头部(header)、空行和请求数据4个部分组成:
get请求:
GET /search?hl=zh-CN&source=hp&q=domety&aq=f&oq= HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/vnd.ms-powerpoint,
application/msword, application/x-silverlight, application/x-shockwave-flash, /
Referer: http://www.google.cn/
Accept-Language: zh-cn
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; TheWorld)
Host: www.google.cn
Connection: Keep-Alive
Cookie: PREF=ID=80a06da87be9ae3c:U=f7167333e2c3b714:NW=1:TM=1261551909:LM=1261551917:S=ybYcq2wpfefs4V9g;
NID=31=ojj8d-IygaEtSxLgaJmqSjVhCspkviJrB6omjamNrSm8lZhKy_yMfO2M4QMRKcH1g0iQv9u-2hfBW7bUFwVh7pGaRUb0RnHcJU37y-
FxlRugatx63JLv7CWMD6UB_O_r
post请求:
POST /api/feed/ HTTP/1.1
Accept-Encoding:gzip
Content-Length:225873
Content-Type:multipart/form-data; boundary=OCqxMF6-ajdifjiqen
Host:www.myhost.com
Connection:Keep-Alive--OCqxMF6-ajdifjiqen
Content-Disposition:form-data;name="username"
Content-Type:text/plain;charset=UTF-8
Content-Transfer-Endcoding:8bitMr.Simple
--OCqxMF6-ajdifjiqen
Content-Disposition:form-data;name="username"
Content-Type:text/plain;charset=UTF-8
Content-Transfer-Endcoding:8bitMr.Simple
响应报文
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:请求资源不存在,举个例子:输入了错误的URL。
500 Internal Server Error:服务器发生不可预期的错误。
503 Server Unavailable:服务器当前不能处理客户端的请求,一段时间后可能恢复正常,举个例子:HTTP/1.1 200 OK(CRLF)。
示例:
HTTP/1.1 200 OK
Date: Sat, 31 Dec 2005 23:59:59 GMT
Content-Type: text/html;charset=UTF-8
Content-Length: 122<html>
<head>
<title>Wrox Homepage</title>
</head>
<body>
<!-- body goes here -->
</body>
</html>
常见的请求头部:
典型的请求头部有:
- Content-Type:请求数据的格式
- Conteent-Lenth:消息长度
- Host:请求的主机名
- User-Agent:发出请求的浏览器类型
- Accept:客户端可以识别的内容类型列表
- Accept-Encoding:客户端可识别的数据编码
- Connection:允许客户端 和服务器指定与请求/响应连接有关的选项
- Transfer-Encoding:为了保证可靠传输,对报文采用了什么编码方式
代码实现
服务端:
- 建立socket监听,循环监听端口,收到连接请求进入新线程处理
- 获取输入流,解析请求(header、参数)
- 处理、返回请求结果
- 关闭输入、输出流、客户端socket连接
http:// 的 HTTP 协议交给 java.net.HttpURLConnection 的子类
sun.net.www.protocol.http.HttpURLConnection 处理
ftp:// 的 FTP 协议交给 URLConnection 的子类 sun.net.www.protocol.ftp.FtpURLConnection 处理
file:// 的 FILE 协议交给 URLConnection 的子类 sun.net.www.protocol.file.FileURLConnection 处理
https:// 的 HTTPS 协议交给 javax.net.ssl.HttpsURLConnection 的子类 sun.net.www.protocol.https.HttpsURLConnectionImpl 处理
com.sun 和 sun 开头包名的类都是 JRE 的底层,被找包在 rt.jar 这个 jar 包中。虽然在 Eclipse 中可以使用反编译工具打开,但是如果想要看这些类带有注释的源代码的话,应该去下载 JDK 所有的源代码。
HTTP缓存
http://my.oschina.net/leejun2005/blog/369148
cookie&session
Cookie或Session技术的应用,解决了HTTP协议的一个问题 -- 无法保持客户状态
cookie是什么
坦白的说,一个cookie就是存储在用户主机浏览器中的一小段文本文件。Cookies是纯文本形式,它们不包含任何可执行代码。一个Web页面或服务器告之浏览器来将这些信息存储并且基于一系列规则在之后的每个请求中都将该信息返回至服务器。Web服务器之后可以利用这些信息来标识用户。多数需要登录的站点通常会在你的认证信息通过后来设置一个cookie,之后只要这个cookie存在并且合法,你就可以自由的浏览这个站点的所有部分。再次,cookie只是包含了数据,就其本身而言并不有害。
创建cookie
通过HTTP的Set-Cookie消息头,Web服务器可以指定存储一个cookie。Set-Cookie消息的格式如下面的字符串(中括号中的部分都是可选的);浏览器把cookie通过HTTP Request中的“Cookie: header”发送给Web服务器。
Set-Cookie:value [ ;expires=date][ ;domain=domain][ ;path=path][ ;secure]
消息头的第一部分,value部分,通常是一个name=value格式的字符串。事实上,原始手册指示这是应该使用的格式,但是浏览器对cookie的所有值并不会按此格式校验。实际上,你可以指定一个不包含等号的字符串并且它同样会被存储。然而,通常性的使用方式是以name=value的格式(并且多数的接口只支持该格式)来指定cookie的值。
当一个cookie存在,并且可选条件允许的话,该cookie的值会在接下来的每个请求中被发送至服务器。cookie的值被存储在名为Cookie的HTTP消息头中,并且只包含了cookie的值,其它的选项全部被去除。例如:
Cookie : value
通过Set-Cookie指定的选项只是应用于浏览器端,一旦选项被设置后便不会被服务器重新取回。cookie的值与Set-Cookie中指定的值是完全一样的字符串;对于这些值不会有更近一步的解析或转码操作。如果在指定的请求中有多个cookies,那么它们会被分号和空格分开,例如:
Cookie:value1 ; value2 ; name1=value1
有效期选项(The expires option)
紧跟cookie值后面的每个选项都以分号和空格分割,并且每个选项都指定cookie何时应该被发送到服务器。第一个选项是expires,其指定了cookie何时不会再被发送到服务器端的,因此该cookie可能会被浏览器删掉。该选项所对应的值是一个格式为Wdy,DD-Mon--YYYY HH:MM:SS GMT的值,例如:
Set-Cookie:name=Nicholas;expires=Sat, 02 May 2009 23:38:25 GMT
在没有expires选项时,cookie的寿命仅限于单一的会话中。浏览器的关闭意味这一次会话的结束,所以会话cookie只存在于浏览器保持打开的状态之下。这就是为什么当你登录到一个web应用时经常看到一个checkbox,询问你是否选择存储你的登录信息:如果你选择是的话,那么一个expires选项会被附加到登录的cookie中。如果expires选项设置了一个过去的时间点,那么这个cookie会被立即删除。
domain选项(The domain option)
下一个选项是domain,指示cookie将要发送到哪个域或那些域中。默认情况下,domain会被设置为创建该cookie的页面所在的域名。domain选项被用来扩展cookie值所要发送域的数量。例如:
Set-Cookie:name=Nicholas;domain=www.baidu.com
path选项(The path option)
另一个控制何时发送Cookie消息头的方式是指定path选项。与domain选项相同的是,path指明了在发Cookie消息头之前必须在请求资源中存在一个URL路径。这个比较是通过将path属性值与请求的URL从头开始逐字符串比较完成的。如果字符匹配,则发送Cookie消息头,例如:
Set-Cookie:name=Nicholas;path=/blog
在这个例子中,path选项值会与/blog,/blogrool等等相匹配;任何以/blog开头的选项都是合法的。要注意的是只有在domain选项核实完毕之后才会对path属性进行比较。path属性的默认值是发送Set-Cookie消息头所对应的URL中的path部分。
secure选项(The secure option)
最后一个选项是secure。不像其它选项,该选项只是一个标记并且没有其它的值。一个secure cookie只有当请求是通过SSL和HTTPS创建时,才会发送到服务器端。这种cookie的内容意指具有很高的价值并且可能潜在的被破解以纯文本形式传输。例如:
Set-Cookie:name=Nicholas;secure
现实中,机密且敏感的信息绝不应该在cookies中存储或传输,因为cookies的整个机制都是原本不安全的。默认情况下,在HTTPS链接上传输的cookies都会被自动添加上secure选项。
session定义
session,中文经常翻译为会话,其本来的含义是指有始有终的一系列动作/消息。然而当session一词与网络协议相关联时,它又往往隐含了“面向连接”和/或“保持状态”这样两个含义,“面向连接”指的是在通信双方在通信之前要先建立一个通信的渠道。“保持状态”则是指通信的一方能够把一系列的消息关联起来,使得消息之间可以互相依赖。 而到了web服务器蓬勃发展的时代,session在web开发语境下的语义又有了新的扩展,它的含义是指一类用来在客户端与服务器之间保持状态的解决方案。
session机制
session机制是一种服务器端的机制,服务器使用一种类似于散列表的结构(也可能就是使用散列表)来保存信息。
当程序需要为某个客户端的请求创建一个session的时候,服务器首先检查这个客户端的请求里是否已包含了一个session标识 - 称为session id,如果已包含一个session id则说明以前已经为此客户端创建过session,服务器就按照session id把这个session检索出来使用(如果检索不到,可能会新建一个),如果客户端请求不包含session id,则为此客户端创建一个session并且生成一个与此session相关联的session id,session id的值应该是一个既不会重复,又不容易被找到规律以仿造的字符串,这个session id将被在本次响应中返回给客户端保存。
保存这个session id的方式可以采用cookie,这样在交互过程中浏览器可以自动的按照规则把这个标识发挥给服务器。一般这个cookie的名字都是类似于SEEESIONID。这种情况下会有一个问题,就是当cookie被禁用后,无法传递sessionid。所以会通过url传参数方式保持会话。
session存放
session存放在服务器内存中,不过session可以通过特殊的方式做持久化管理。
Android中的Http请求
Android中提供了两种执行网络请求的方式,一种是使用apache的HttpClient,另一个是用java的HttpURLConnection。
HttpClient
在Android开发中,android sdk附带了apache的httpclient,可以使用它的对象来执行get和post调用。一般使用步骤如下:
- 使用DefaultHttpClient类实例化HttpClient对象;
- 创建HttpGet或HttpPost对象,将要请求的URL通过构造方法传入HttpGet或HttpPost对象;
- 调用execute方法发送Get或Post请求,并返回HttpResponse对象;
- 通过HttpResponse接口的getEntity方法返回响应信息,并通过相应的处理。
HttpURLConnection
android 2.2版本及之前用HttpClient,而在2.3版本之后,HttpURLConnection则是最佳选择。它的压缩和缓存机制可以有效地减少网络访问的流量,在Android 6.0中,HttpClient库已经被移除。
private void sendRequest(String url) throws IOException {
InputStream is = null;
try {
URL newUrl = new URL(url);
HttpURLConnection conn = (HttpURLConnection) newUrl.openConnection();
// 设置读取超时为10秒
conn.setReadTimeout(10000);
// 设置链接超时为15秒
conn.setConnectTimeout(15000);
// 设置请求方式
conn.setRequestMethod("POST");
// 接收输入流
conn.setDoInput(true);
// 启动输入流,当需要传递参数时需要开启
conn.setDoOutput(true);
// 添加Header
conn.ssetRequestProperty("Connection", "Keep-Alive");
// 添加请求参数
List paramsList = new ArrayList();
paramsList.add(new BasicNameValuePair("username", "name"));
paramsList.add(new BasicNameValuePair("pwd", "pwd"));
writeParams(conn,getOutputStream(), paramsList);
conn.connect();
is = conn.getInputStream();
...
} finally {
if (is != null) {
is.close();
}
}
}