zoukankan      html  css  js  c++  java
  • 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客户端,为了代码简洁,省略了资源关闭和异常处理:

    public static void main(String[] args) throws Exception {
    	// 地址localhost,端口号8080  
    	Socket socket = new Socket("localhost", 8080);    
    
    	// 请求服务器  
    	OutputStream out = socket.getOutputStream();  
    	PrintWriter pw = new PrintWriter(out);  
    	pw.println("GET /Test/test.jsp HTTP/1.1");  // 请求的第一行Request-Line,需要写请求的URL(/Test/test.jsp)  
    	pw.println("Host: localhost:8080");  // 请求头,Host是必须的  
    	pw.println();  // 一定要有个空行表示请求结束  
    	pw.flush();  // 提交请求  
    	      
    	// 获取服务器响应  
    	InputStream is = socket.getInputStream();
    	InputStreamReader reader = new InputStreamReader(is);
    	    
    	// 输出响应内容    
    	while (true) {
    		System.out.print((char)reader.read());
    	}
    }

    上面的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。

    <% 
    Cookie cookie1 = new Cookie("name", "xxg");
    response.addCookie(cookie1);  // Cookie在浏览器关闭时失效
    
    Cookie cookie2 = new Cookie("age", "22");
    cookie2.setMaxAge(60 * 60 * 24 * 7); // 设置Cookie有效期7天
    response.addCookie(cookie2);
    %>
    <html>
      <body>
        <h1>
        Hello
        </h1>
      </body>
    </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:

    <html>
      <body>
        <h1>
        <%
        if(session.getAttribute("user") == null) {
        	session.setAttribute("user", "xxg");
        	out.print("null");
        }
        else {
        	out.print(session.getAttribute("user"));
        }
        %> 
        </h1>
      </body>
    </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");

    public static void main(String[] args) throws Exception
    {
    	// 地址localhost,端口号8080  
    	Socket socket = new Socket("localhost", 8080);    
    
    	// 请求服务器  
    	OutputStream out = socket.getOutputStream();  
    	PrintWriter pw = new PrintWriter(out);  
    	pw.println("GET /Test/test.jsp HTTP/1.1");  // 请求的第一行Request-Line,需要写请求的URL(/Test/test.jsp)  
    	pw.println("Host: localhost:8080");  // 请求头,Host是必须的  
    	pw.println("Cookie: JSESSIONID=5C196487B8C2FA6742CB7B6E8DC63935");  // Session ID
    	pw.println();  // 一定要有个空行表示请求结束  
    	pw.flush();  // 提交请求  
    
    	// 获取服务器响应  
    	InputStream is = socket.getInputStream();
    	InputStreamReader reader = new InputStreamReader(is);
    
    	// 输出响应内容    
    	while (true) {
    		System.out.print((char)reader.read());
    	}
    }

    此时请求加入了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




  • 相关阅读:
    Atitit topic index Abt 150 toic [原]Atitit hi dev eff topic by use dsl sql coll op 提升开发效率sql ds
    Atitit xml转json总结 目录 1.1. XML和JSON之间没有直接映射;元素类型问题 1 1.2. Xml与json的对应关系 2 1.3. 范例 2 2. Jsonlib的问题,,不
    Atitit stomp.js conn连接activemq 目录 1.1. activemq 启动,已经默认开启了stomp ws的接口。。地址是 1 1.2. Js 客户端代码 1 1.3
    Atitit 业务领域体系分类 目录 1. 按照互联网企业类型以及只是体系类的分类 2 2. 电子商务 2 3. **通信类社交 Im类 em 2 4. **信息搜索类爬虫 2 4.1. 媒体
    atitit software sys 软件技术领域工业体系.docx 目录 1. 技术领域一级大类10大类 2 2. 理论与软件设计方法学 2 2.1. 计算机原理 计算机科学导论 2 2.2.
    Atitit api design Usability simple 易用性之简单化设计 目录 1. 理论原则 2 1.1. 概念简单 2 1.2. 切换到了“write less, do more
    Atitit 远程工作的几种办公模式 目录 1. 未来的趋势 远程办公 1 1.1. 遥远的阴影 1 1.2. 一个单中心的团队,是一个团队,每个人都被共处于同一物理位置。 2 1.3. 一个多站
    Atitit 保证产品易用性的方法总结 目录 1. 什么是易用性 易学 易见 三角关系 1 2. 易用性原理 三原则 易见 映射 反馈 2 2.1. 易见 Visibility 可读性 2 2.2.
    Atitit 高级人员要看哪些源码 目录 1. Ati看过的源码 1 1.1. Ui类 1 1.2. Mvc类 1 1.3. 数据库类 1 1.4. 算法类 1 2. 看源码的意义 2 2.1. 一
    Atitit 初级 中级 高级 软件工程师的区别 非功能性需求 目录 1. 初级 业务功能 1 1.1. 中级 独立完成业务功能 已经非常见api功能 更加广阔 1 2. 高级 非功能性需求
  • 原文地址:https://www.cnblogs.com/riasky/p/3473310.html
Copyright © 2011-2022 走看看