最近在开发项目的过程中,遇到android与web服务器要在同一session下通信的问题。
在解决问题前先回顾下Session与Cookie:
Cookie和Session都为了用来保存状态信息,都是保存客户端状态的机制,它们都是为了解决HTTP无状态的问题而所做的努力。
Session可以用Cookie来实现,也可以用URL回写的机制来实现。
Cookie和Session有以下明显的不同点:
1)Cookie将状态保存在客户端,Session将状态保存在服务器端;
2)Cookies是服务器在本地机器上存储的小段文本并随每一个请求发送至同一个服务器。网络服务器用HTTP头向客户端发送cookies,在客户终端,浏览器解析这些cookies并将它们保存为一个本地文件,它会自动将同一服务器的任何请求缚上这些cookies。
3)Session是针对每一个用户的,变量的值保存在服务器上,用一个sessionID来区分是不同用户session变量,这个值是通过用户的浏览器在访问的时候返回给服务器,当客户禁用cookie时,这个值也可能设置为由get来返回给服务器;
4)就安全性来说:当你访问一个使用session 的站点,同时在自己机器上建立一个cookie,建议在服务器端的SESSION机制更安全些.因为它不会任意读取客户存储的信息。
Session机制
Session机制是一种服务器端的机制,服务器使用一种类似于散列表的结构(也可能就是使用散列表)来保存信息。
当程序需要为某个客户端的请求创建一个session的时候,服务器首先检查这个客户端的请求里是否已包含了一个session标识 - 称为 session id,如果已包含一个session id则说明以前已经为此客户端创建过session,服务器就按照session id把这个 session检索出来使用(如果检索不到,可能会新建一个),如果客户端请求不包含session id,则为此客户端创建一个session并且生成一个与此session相关联的session id,session id的值应该是一个既不会重复,又不容易被找到规律以仿造的字符串,这个 session id将被在本次响应中返回给客户端保存。
Session的实现方式
1 ) 使用Cookie来实现
服务器给每个Session分配一个唯一的JSESSIONID,并通过Cookie发送给客户端。
当客户端发起新的请求的时候,将在Cookie头中携带这个JSESSIONID。这样服务器能够找到这个客户端对应的Session。
2 )使用URL回显来实现
URL回写是指服务器在发送给浏览器页面的所有链接中都携带JSESSIONID的参数,这样客户端点击任何一个链接都会把JSESSIONID带给服务器。
如果直接在浏览器中输入url来请求资源,Session是匹配不到的。
Tomcat对 Session的实现,是一开始同时使用Cookie和URL回写机制,如果发现客户端支持Cookie,就继续使用Cookie,停止使用URL回写。如果发现Cookie被禁用,就一直使用URL回写。jsp开发处理到Session的时候,对页面中的链接记得使用 response.encodeURL() 。
回顾完Session和Cookie,我们来说说为什么手机端与服务器交互没有实现在同一session下?
1)原因很简单,就是因为android手机端在访问web服务器时,没有给http请求头部设置sessionID,而使用web浏览器作为客户端访问服务器时,在客户端每次发起请求的时候,都会将交互中的sessionID:JSESSIONID设置在Cookie头中携带过去,服务器根据这个sessionID获取对应的Session,而不是重新创建一个新Session(除了这个Session失效)。
以java.net.HttpURLConnection发起请求为例:
获取Cookie:
URL url = new URL(requrl);
HttpURLConnection con= (HttpURLConnection) url.openConnection();
// 取得sessionid.
String cookieval = con.getHeaderField("set-cookie");
String sessionid;
if(cookieval != null) {
sessionid = cookieval.substring(0, cookieval.indexOf(";"));
}
//sessionid值格式:JSESSIONID=AD5F5C9EEB16C71EC3725DBF209F6178,是键值对,不是单指值
发送设置cookie:
URL url = new URL(requrl);
HttpURLConnectioncon= (HttpURLConnection) url.openConnection();
if(sessionid != null) {
con.setRequestProperty("cookie", sessionid);
}
只要设置了sessionID,这样web服务器在接受请求的时候就会自动搜索对应的session了,从而保证了在同一会话Session。
然而如何保证客户端的session不过期呢?
方案1、将session 设置成拥挤不过期,这样确实可以解决客户端的session 过期的问题,但是不推荐。这样服务器端session一直不销毁,会占用内存,越来越来越多。
方案2.心跳机制。这是最常见的客户端保持会话不过期的方法。简单的做法就是写个定时器,美隔几分钟发送广播,收到广播后收客户端去访问服务器。当然也有问题。这个方式。举个例子说下他的问题吧。比如虽然写了个定时器去访问服务器,但是如果这段时间(假如30分钟),客户端正好把网络给关了,31分钟后客户端又打开了网络连接,由于30分钟没有访问服务器 你调用A()方法的时候返回的结果是{“error”:"login"},然后你根据结果再去调用B() 登陆方法,登陆成功后,在自动A()方法。这样的话,每次访问网络都要更这个B()登陆方法,代码臃肿。而且费电。
方法3:服务器自动登登陆的方法
客户端访问服务器事,同时带着用户名,和密码,还有cookie(session_id),服务器先判断session_id 是否过期,如果过期,在判读参数中有用户名和密码,如果有,就在调用一下登录的方法,登录成功后,就接着操作。。这种方法的缺点就是每次都要带个账号和密码,稍微有点耗流量。