Java Socket实现HTTP客户端来理解Session和Cookie的区别和联系

HTTP协议本身是无状态的,即使是同一台电脑同一个浏览器打开同一个页面两次,服务器不知道这两次请求是同一个客户端发送过来的,两次请求是完全独立的。例如,第一次请求时已经登录了,第二次再请求服务器会“忘了”你已经登录过。

为了解决这个问题,就有了Cookie和Session。它们的出现是为了让服务器“记住”之前这个客户端的一些数据,让HTTP保持状态。

下面通过Java Socket实现的HTTP客户端来理解二者之间的原理,以及它们的区别和联系。

HTTP客户端:

Java实现的HTTP客户端有很多种,例如java.NET包中的HttpURLConnection,Apache的开源工具HttpComponents。这些都是功能比较完善的HTTP客户端,但是为了看到最底层的HTTP请求和响应,这里用Socket来实现客户端。

下面是Java Socket实现的一个HTTP客户端,为了代码简洁,省略了资源关闭和异常处理:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. public static void main(String[] args) throws Exception {  
  2.     // 地址localhost,端口号8080    
  3.     Socket socket = new Socket("localhost"8080);      
  4.   
  5.     // 请求服务器    
  6.     OutputStream out = socket.getOutputStream();    
  7.     PrintWriter pw = new PrintWriter(out);    
  8.     pw.println("GET /Test/test.jsp HTTP/1.1");  // 请求的第一行Request-Line,需要写请求的URL(/Test/test.jsp)    
  9.     pw.println("Host: localhost:8080");  // 请求头,Host是必须的    
  10.     pw.println();  // 一定要有个空行表示请求结束    
  11.     pw.flush();  // 提交请求    
  12.             
  13.     // 获取服务器响应    
  14.     InputStream is = socket.getInputStream();  
  15.     InputStreamReader reader = new InputStreamReader(is);  
  16.           
  17.     // 输出响应内容      
  18.     while (true) {  
  19.         System.out.print((char)reader.read());  
  20.     }  
  21. }  
上面的HTTP客户端通过Socket发送一个最简单的HTTP GET请求到服务器的localhost:8080/Test/test.jsp页面:

GET /Test/test.jsp HTTP/1.1
Host: localhost:8080

然后将服务器的HTTP响应输出。

HTTP服务器:

服务器使用的是Tomcat,页面是上面客户端请求的页面/Test/test.jsp。

Cookie:

修改/Test/test.jsp页面,通过response.addCookie(Cookie cookie)来设置Cookie。

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <%   
  2. Cookie cookie1 = new Cookie("name""xxg");  
  3. response.addCookie(cookie1);  // Cookie在浏览器关闭时失效  
  4.   
  5. Cookie cookie2 = new Cookie("age""22");  
  6. cookie2.setMaxAge(60 * 60 * 24 * 7); // 设置Cookie有效期7天  
  7. response.addCookie(cookie2);  
  8. %>  
  9. <html>  
  10.   <body>  
  11.     <h1>  
  12.     Hello  
  13.     </h1>  
  14.   </body>  
  15. </html>  
运行客户端重新,用HTTP客户端来输出服务器发回的响应:

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Set-Cookie: JSESSIONID=3B3292C40C9D100E0F2FDC42293225C8; Path=/Test/; HttpOnly
Set-Cookie: name=xxg
Set-Cookie: age=22; Expires=Wed, 18-Dec-2013 05:19:05 GMT

Content-Type: text/html;charset=ISO-8859-1
Content-Length: 72
Date: Wed, 11 Dec 2013 05:19:05 GMT

<html>
  <body>
    <h1>
    Hello
    </h1>
  </body>
</html>

可以看到在响应的Header中有Set-Cookie项,这是服务器将需要设置的Cookie发给客户端,让客户端来保存,当下次再请求时,把Cookie放在请求的Header中发送给服务器。这些在浏览器中都是自动完成。

Session:

Session可以通过session.setAttribute(String name, Object value)来设置,它保存在服务器上,value可以是任何Java类型的对象。当第一次访问jsp时,无论代码中有没有调用session.setAttribute()设置session,都会默认创建Session。

由于HTTP是无状态的,要想知道服务器上某个Session对应的是哪个客户端,就要通过Session ID。

Session ID是由服务器生成,发送给客户端,客户端在以后的请求中带着这个Session ID,就能在服务器中找到对应的Session。

这就类似于第一次去理发店办卡,卡上只有卡号,卡中的余额、消费记录等数据是存在理发店而不是卡中,下次再去的话带着卡,理发店就能查找到对应的记录。

Session ID是如何由服务器发给客户端,再由客户端发给服务器的?一般有两种方式:

一种是URL重写,这种方式不太常用,也不怎么好用,这里也不再详解;

另一种就是最常用的方式Cookie。

在上面输出的HTTP响应中可以找到这样一个Cookie:

Set-Cookie: JSESSIONID=3B3292C40C9D100E0F2FDC42293225C8; Path=/Test/; HttpOnly

这就是服务器发回给客户端的Session ID。由于这个Cookie没有设置Expires有效期,所以在浏览器关闭后就会失效。这也就是Session在浏览器关闭后失效的原因。实际上Session还是保存在服务器上的,并没有真正在服务器上消失,只是对浏览器而言已经重新创建Session并获取Session ID。

修改服务器/Test/test.jsp:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <html>  
  2.   <body>  
  3.     <h1>  
  4.     <%  
  5.     if(session.getAttribute("user") == null) {  
  6.         session.setAttribute("user""xxg");  
  7.         out.print("null");  
  8.     }  
  9.     else {  
  10.         out.print(session.getAttribute("user"));  
  11.     }  
  12.     %>   
  13.     </h1>  
  14.   </body>  
  15. </html>  
当Session中user为空时创建,输出null,不为空时输出放进去的user。

如果用浏览器打开这个页面的话,第一次访问时页面显示null,再刷新一下,就会显示xxg:


但是使用上面Java写的HTTP客户端请求这个页面,无论请求多少次,都会输出null:

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Set-Cookie: JSESSIONID=5C196487B8C2FA6742CB7B6E8DC63935; Path=/Test/; HttpOnly
Content-Type: text/html;charset=ISO-8859-1
Content-Length: 70
Date: Wed, 11 Dec 2013 06:28:41 GMT

<html>
  <body>
    <h1>
    null 
    </h1>
  </body>
</html>

原因就是上面的HTTP客户端并没有把Session ID放在请求中发送给服务器,也就是去理发忘了带卡。

现在复制出上面响应得到的Session ID:

JSESSIONID=5C196487B8C2FA6742CB7B6E8DC63935

在HTTP请求中中加入一个Header,将Seesion ID发回给服务器:

pw.println("Cookie: JSESSIONID=5C196487B8C2FA6742CB7B6E8DC63935");

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. public static void main(String[] args) throws Exception  
  2. {  
  3.     // 地址localhost,端口号8080    
  4.     Socket socket = new Socket("localhost"8080);      
  5.   
  6.     // 请求服务器    
  7.     OutputStream out = socket.getOutputStream();    
  8.     PrintWriter pw = new PrintWriter(out);    
  9.     pw.println("GET /Test/test.jsp HTTP/1.1");  // 请求的第一行Request-Line,需要写请求的URL(/Test/test.jsp)    
  10.     pw.println("Host: localhost:8080");  // 请求头,Host是必须的    
  11.     pw.println("Cookie: JSESSIONID=5C196487B8C2FA6742CB7B6E8DC63935");  // Session ID  
  12.     pw.println();  // 一定要有个空行表示请求结束    
  13.     pw.flush();  // 提交请求    
  14.   
  15.     // 获取服务器响应    
  16.     InputStream is = socket.getInputStream();  
  17.     InputStreamReader reader = new InputStreamReader(is);  
  18.   
  19.     // 输出响应内容      
  20.     while (true) {  
  21.         System.out.print((char)reader.read());  
  22.     }  
  23. }  

此时请求加入了Session ID的Cookie:

GET /Test/test.jsp HTTP/1.1
Host: localhost:8080
Cookie: JSESSIONID=5C196487B8C2FA6742CB7B6E8DC63935

输出HTTP响应结果:

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=ISO-8859-1
Content-Length: 69
Date: Wed, 11 Dec 2013 06:32:19 GMT

<html>
  <body>
    <h1>
    xxg 
    </h1>
  </body>
</html>

这样Session才有了效果。


作者:叉叉哥   转载请注明出处:http://blog.csdn.net/xiao__gui/article/details/17298437

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值