精华内容
下载资源
问答
  • 2019-12-26 22:19:53

    为什么有session?

      首先大家知道,http协议是无状态的,即你连续访问某个网页100次和访问1次对服务器来说是没有区别对待的,因为它记不住你。 
      那么,在一些场合,确实需要服务器记住当前用户怎么办?比如用户登录邮箱后,接下来要收邮件、写邮件,总不能每次操作都让用户输入用户名和密码吧,为了解决这个问题,session的方案就被提了出来,事实上它并不是什么新技术,而且也不能脱离http协议以及任何现有的web技术。 
      原理很简单,假设你访问网页时就像逛澡堂,第一次进去你是没有钥匙的,这个时候你交了钱服务台就分配一把钥匙给你,你走到哪里都要带上,因为这是你身份的唯一标识,接下来你用这把钥匙可以去打开一个专有的储物柜存储你的衣物,游完泳,你再用钥匙去打开柜子拿出衣物,最后离开游泳池时,把钥匙归还,你的这次游泳的过程就是一次session,或者叫做会话,在这个例子中,钥匙就是session的key,而储物柜可以理解为存储用户会话信息的介质。 
      那么在web server中如何实现session呢?想必看了上面的例子你会很容易理解,主要是解决两个问题,一个是钥匙的问题,一个是存储用户信息的问题。对于第一个问题,即什么东西可以让你每次请求都会自动带到服务器呢?如果你比较了解http协议,那么答案一目了然,就是cookie,如果你想为用户建立一次会话,可以在用户授权成功时给他一个cookie,叫做会话id,它当然是唯一的,比如PHP就会为建立会话的用户默认set一个名为phpsessid,值看起来为一个随机字符串的cookie,如果下次发现用户带了这个cookie,服务器就知道,哎呀,刚刚这位顾客来了。 
      剩下的是解决第二个问题,即如何存储用户的信息,服务器知道会话id为abc的用户来了,那abc想存储自己的私人信息,比如购物车信息,如何处理?这个时候可以用内存、也可以用文件,也可以用数据库了,但有个要求是,数据需要用用户的会话id即可取到,比如php就默认会把会话id为abc的用户会话数据存储到/tmp/phpsess_abc【1】的文件里面,每次读取都要反序列化程序可以理解的数据,写的时候又需要序列化为持久的数据格式。

    如何实现session的共享?

      首先我们应该明白,为什么要实现共享,如果你的网站是存放在一个机器上,那么是不存在这个问题的,因为会话数据就在这台机器,但是如果你使用了负载均衡把请求分发到不同的机器呢?这个时候会话id在客户端是没有问题的,但是如果用户的两次请求到了两台不同的机器,而它的session数据可能存在其中一台机器,这个时候就会出现取不到session数据的情况,于是session的共享就成了一个问题。 
      事实上,各种web框架早已考虑到这个问题,比如asp.NET,是支持通过配置文件修改session的存储介质为sql server的,所有机器的会话数据都从同一个数据库读,就不会存在不一致的问题;php支持把会话数据存储到某台memcache服务器,你也可以手工把session文件存放的目录改为nfs网络文件系统,从而实现文件的跨机器共享。 
      还有一个简单的办法可以用于会话信息不会频繁变更的情况,在机器a设置用户会话的时候,把会话数据post到机器b的一个cgi,机器b的cgi把会话数据存下来,这样机器a和b都会有同一份session数据的拷贝。【2】  

    SESSION 的数据保存在哪里呢?

    PHP中的session存储

      SESSION 的数据保存在哪里呢? 
      当然是在服务器端,但不是保存在内存中,而是保存在文件或数据库中。 
       默认情况下,PHP.ini 中设置的 SESSION 保存方式是 files(session.save_handler = files),即使用读写文件的方式保存 SESSION 数据,而 SESSION 文件保存的目录由 session.save_path 指定,文件名以 sess_ 为前缀,后跟 SESSION ID,如:sess_c72665af28a8b14c0fe11afe3b59b51b。文件中的数据即是序列化之后的 SESSION 数据了。 
       如果访问量大,可能产生的 SESSION 文件会比较多,这时可以设置分级目录进行 SESSION 文件的保存,效率会提高很多,设置方法为:session.save_path="N;/save_path",N 为分级的级数,save_path 为开始目录。 
       当写入 SESSION 数据的时候,php 会获取到客户端的 SESSION_ID,然后根据这个 SESSION ID 到指定的 SESSION 文件保存目录中找到相应的 SESSION 文件,不存在则创建之,最后将数据序列化之后写入文件【3】。读取 SESSION 数据是也是类似的操作流程,对读出来的数据需要进行解序列化,生成相应的 SESSION 变量。

    Java中的session存储

      sessionid是一个会话的key,浏览器第一次访问服务器会在服务器端生成一个session,有一个sessionid和它对应。tomcat生成的sessionid叫做jsessionid。 
      session在访问tomcat服务器HttpServletRequest的getSession(true)的时候创建,tomcat的ManagerBase类提供创建sessionid的方法:随机数+时间+jvmid。 
      存储在服务器的内存中,tomcat的StandardManager类将session存储在内存中,也可以持久化到file,数据库,memcache,redis等。客户端只保存sessionid到cookie中,而不会保存session,session销毁只能通过invalidate或超时,关掉浏览器并不会关闭session。


      那么Session在何时创建呢?当然还是在服务器端程序运行的过程中创建的,不同语言实现的应用程序有不同创建Session的方法,而在Java中是通过调用HttpServletRequest的getSession方法(使用true作为参数)创建的。【4】在创建了Session的同时,服务器会为该Session生成唯一的Session id,而这个Session id在随后的请求中会被用来重新获得已经创建的Session;在Session被创建之后,就可以调用Session相关的方法往Session中增加内容了,而这些内容只会保存在服务器中,发到客户端的只有Session id;当客户端再次发送请求的时候,会将这个Session id带上,服务器接受到请求之后就会依据Session id找到相应的Session,从而再次使用之。


      创建:sessionid第一次产生是在直到某server端程序调用 HttpServletRequest.getSession(true)这样的语句时才被创建。 
      删除:超时;程序调用HttpSession.invalidate();程序关闭。 
      session存放在哪里:服务器端的内存中。【5】不过session可以通过特殊的方式做持久化管理(memcache,redis)。 
      session的id是从哪里来的,sessionID是如何使用的:当客户端第一次请求session对象时候,服务器会为客户端创建一个session,并将通过特殊算法算出一个session的ID,用来标识该session对象。 
      session会因为浏览器的关闭而删除吗?不会,session只会通过上面提到的方式去关闭。【6】

    博主注

    【1】这里需要说明下。博主在Windows下wamp中查看到wamp安装目录下有tmp目录,其中session数据保存的文件以”sess_”作为前缀命名。在CentOS中nginx+php-fpm环境中,配置session的保存路径(在php.ini中配置session.save_path的值,注意这个路径需要Web服务器进程所属用户有权操作-读写操作)后,保存的session文件同样以“sess_”作为前缀命名。 
    【2】除了上述提及的方法外,解决session共享问题还有这样一种方式:(实质上并不是通过session的共享来解决的)这里以nginx为例,将用户请求分发到了不同机器上,那么我们只需要固定,同一用户请求分发到同一机器上进行处理,即这一次用户来请求服务器了,那么下一次它再来的时候,同样也请求也被分发到与上一次相同的服务器。这样就确保了同一用户不会因为请求分发到不同机器上而获取不到session数据的问题了。 
    【3】后台服务端可以将数据保存在session中,对于php而言,是将数据序列化后保存在文件中,内容如下:

    USER|a:5:{s:7:"user_id";s:6:"512071";s:8:"username";s:18:"未命名的昵称";s:5:"phone";s:11:"18888888888";s:9:"last_time";s:19:"2017-06-30 15:45:55";s:6:"is_vip";s:1:"0";}noLoginUser|a:2:{s:10:"session_id";s:40:"captcha_81cd8166e5a84a56605c5903466416da";s:11:"verify_code";s:4:"9626";}
    • 1

    【4】从浏览器打开访问了某一个网站,关闭浏览器。这样的操作我们算一次“会话”。所以大部分就会认为用户访问了网站就会产生session ID。实际上不然。例如:在Java中我们需要调用HttpServletRequest的getSession方法创建session。而在PHP中需要session_start()一下,服务器才会将存有session ID的cookie回传回去。否则不会有什么session产生。 
    【5】“session存放在哪里:服务器端的内存中。”指的是Tomcat保存session的方式。对于PHP而言是保存在文件中。上述有提及。 
    【6】session不会因为浏览器的关闭而删除。但是存有session ID的cookie的默认过期时间是会话级别。也就是用户关闭了浏览器,那么存储在客户端的session ID便会丢失,但是存储在服务器端的session数据并不会被立即删除。从客户端即浏览器看来,好像session被删除了一样(因为我们丢失了session ID,找不到原来的session数据了)。

    更多相关内容
  • 本文实例讲述了PHP基于cookie与session统计网站访问量并输出显示的方法。分享给大家供大家参考,具体如下: <?php $f_open = fopen("count.txt","r+"); //打开指定的文件 $count = fgets($f_open); //...
  • cookie在客户的浏览器上,session存在服务器上 cookie是不安全的,且有失效时间 session是在cookie的基础上,服务端设置session时会向浏览器发送设置一个设置cookie的请求,这个cookie包括session的id当访问服务端时...
  • Web开发中的Session详解及原理分析

    千次阅读 2021-08-09 03:48:28
    原标题:Web开发中的Session详解及原理分析一. HttpSession机制1. HTTP协议与HttpSession的状态保持Session经常被翻译为会话,其本来的含义是指有始有终的一系列动作/消息。比如打电话时,从拿起电话拨号到挂断电话...

    原标题:Web开发中的Session详解及原理分析

    一. HttpSession机制

    1. HTTP协议与HttpSession的状态保持

    Session经常被翻译为会话,其本来的含义是指有始有终的一系列动作/消息。比如打电话时,从拿起电话拨号到挂断电话这中间的一系列过程可以称之为一个Session。而在网络中,Session是指从一个浏览器窗口打开再到关闭的这个期间。

    互联网应用层协议基本都是基于 HTTP 和 HTTPS 协议的,它们的本身都是无状态的, 也就是只负责网络的请求和响应。 我们只需要告诉服务器我们需要什么,服务器就会给我们返回相应的资源。 如果没有额外处理的话,服务器并不知道发起请求的人是谁,也无法根据请求者是谁来给你展现和你相关的内容了。

    HTTP 协议之所以一开始被设计成这样,还是有一些历史原因的,当时的互联网多用于学术交流,只用于文章信息的展现,远没有像现在这么丰富多彩。所以在当时的背景下, HTTP 协议被设计成这样,其实也是很符合它的场景的。

    但随着互联网应用越来越广泛,应用的形式也变得越来越多,我们的 Web 应用已不只限于提供简单的信息展现了,还需要用户能够与服务器进行交互,比如能够登录,可以在留言回复、可以进行购物、社交等。 这就需要 HTTP 协议能够记录用户的状态,而这个状态就可以由HttpSession来进行保存。

    2. HttpSession工作原理

    0d6565b6cdd24d2dcde5e5296d4803b0.png

    Client(浏览器)第一次发送请求的时候,Web Container(Tomcat、Jetty等服务器容器)会生成唯一的Session ID(这个Session ID包括随机数+时间+JVM ID),并将其返回给Client(在Web Container返回给Client的Response中),但是Web Container上的这个HttpSession是临时的。

    接下来Client在每次发送请求给服务器时,都会将Session ID发送给Web Container,这样Web Container就能很容易区分出是哪个Client。

    Web Container会使用这个Session ID,找到对应的HttpSession,并将这个Request与这个HttpSession联系起来。

    当用户第一次访问Servlet时,服务器端会给用户客户端创建一个独立的Session; 该Session会有一个Session ID(JSESSIONID),格式如:JSESSIONID=7F149950097E7B5B41B390436497CD21,其中JSESSIONID是固定的。而这个Session ID在响应浏览器的时候会被存储到Cookie中,从而被保存到浏览器中; 而后面的value值对应的则是给该客户端新创建的session的ID; 当用户再一次访问Servlet时,请求C都会携带着Cookie中的SessionID去访问; 服务器会根据这个Session ID去查看是否有对应的Session对象; 如果有就拿出来使用;如果没有就创建一个Session(相当于用户第一次访问)。

    3. HttpSession生命周期:

    3.1 什么时候创建HttpSession

    (1). 对于JSP而言: 是否浏览器访问服务端的任何一个JSP,服务器都会立即创建一个HttpSession对象呢? 不一定。 ①.若当前的JSP或Servlet,是客户端访问当前WEB应用的第一个资源,且JSP的page指令中的session属性为false时,服务器是不会为JSP创建HttpSession对象的; ②.若当前JSP不是客户端访问的WEB应用的第一个资源,且其他页面已经创建了一个HttpSession对象,则服务器也不会为当前JSP创建一个新的HttpSession对象,而是会把和当前会话关联的那个HttpSession对象返回给当前的JSP页面。

    (2). 对于Servlet而言: 若Servlet是客户端访问的第一个WEB应用资源,只有调用了request.getSession()或request.getSession(true) 才会创建HttpSession对象。

    3.2 什么时候销毁HttpSession对象:

    (1). 直接调用HttpSession的invalidate()方法,会使HttpSession失效;

    (2). 服务器卸载了当前Web应用;

    (3). 超出了HttpSession的过期时间。

    #代码中设置session过期时间的方式 session.setMaxInactiveInterval(5); #web.xml中设置session过期时间的方式 30

    注: 由于会有越来越多的用户访问服务器,因此Session也会越来越多。为了防止内存溢出,服务器会把长时间内没有活跃的Session从内存中删除,而这个时间就是Session的超时时间。如果超过了超时时间没访问过服务器,Session就自动失效了。

    4. Session的特点

    Session数据保存在服务器端; Session中可以保存任意类型的数据; Session默认的生命周期是30分钟,可以手动设置更长或更短的时间。

    二. Cookie机制

    1. 什么是Cookie

    Cookie翻译成中文是甜饼的意思,其实就是一个小型的文本文件,用来保存一些简单的信息(浏览器对Cookie的内存大小是有限制的)。Cookie由服务器端生成,并且会发送给 User-Agent (一般是浏览器),服务器一般会告诉浏览器设置一下Cookie,然后浏览器会自动将该 Cookie 以key/value 的格式保存到浏览器的某个目录下;等到下次请求同一网站时,浏览器会自动通过请求头发送该Cookie给服务器,前提是浏览器设置了启用Cookie功能。

    2. 为什么要有Cookie

    Web应用程序是使用HTTP协议来传输数据的,而HTTP协议是无状态的协议,也就是说一旦数据交换完毕,客户端与服务器端的连接就会关闭,等再次交换数据就需要建立新的连接,这就意味着服务器无法从连接上跟踪会话。比如我们登陆一个网站的时候,会提醒你要不要记住账户和密码,这样下次来你就不用再次输入账号密码了,这就是Cookie的作用。当我们再次访问的时候,服务器会直接根据我们的Cookie来获取上一次取过的东西。

    3. Cookie 的特点

    3.1 Cookie 的过期时间

    我们每次发送请求的时候,都会根据domain来设置相应的Cookie。Cookie有永久的,也有临时的,每个浏览器都有自己的Cookie,我们可以通过设置expires、max-age来设置保存日期,如果不设置的话默认是临时存储,也就是说关闭浏览器后Cookie就会消失。

    document.cookie = 'expires=时间/max-age=秒'

    3.2 Cookie要满足同源策略

    虽然网站news.baidu.com与www.baidu.com同属于Baidu,但是域名却不一样,也就是说这两者之间是不能互相操作彼此Cookie的。只有域名和path都必须一样,才能相互访问彼此的Cooki。但是需要注意不同浏览器对path访问规定是不一样的,对于chrome,path必须为当前目录,设置为其他目录无效,当前页面只能访问当前目录的Cookie`。

    3.3 Cookie内存大小受限制

    Cookie有个数和大小的限制,大小一般是4k,但是不同的浏览器,具体的Cookie大小也是不同的。

    Firefox和Safari允许Cookie多达4097个字节,包括名(name)、值(value)和等号;

    Opera允许Cookie多达4096个字节,包括名(name)、值(value)和等号;

    Internet Explorer允许Cookie多达4095个字节,包括名(name)、值(value)和等号。

    6d24b9f9cf4089d136cc13185ca019ce.png

    3.4 Cookie的安全性

    Cookie是保存在浏览器本地的,是可以被修改的,所以敏感的数据不要放在Cookie里。

    三. Session共享

    1. Session存在的问题

    HttpSession是通过Servlet容器创建和管理的,像Tomcat/Jetty都是保存在内存中的。但是如果我们将Web应用横向扩展成分布式的集群,然后利用LVS或Nginx进行负载均衡,那么对来自同一用户的Http请求,将有可能被负载分发到两个不同的服务器实例中去。那么如何保证不同实例间的Session共享,就成为一个不得不解决的问题。

    最简单的解决方法就是把Session数据保存到内存以外的一个统一的地方,例如Memcached/Redis中。那么问题又来了,如何替换掉Servlet容器,来创建和管理HttpSession呢?

    2. Session共享的实现方案

    利用Servlet容器提供的插件功能,自定义HttpSession的创建和管理策略,并通过配置的方式替换掉默认的策略。不过这种方式有个缺点,就是需要耦合Tomcat/Jetty等Servlet容器的代码。这方面其实早就有开源项目了,例如memcached-session-manager,以及tomcat-redis-session-manager,不过这暂时都只支持Tomcat6/Tomcat7。

    配置Nginx的负载均衡算法为ip_hash,这样每个请求按访问IP的hash结果分配,这样来自同一个IP的访客就会固定访问一个后端服务器,有效解决了动态网页存在的Session共享问题。

    使用Shiro管理Session,可以用Redis来实现Shiro 的SessionDao接口,这样Session便归Redis来保存了。

    设计一个Filter,利用HttpServletRequestWrapper,实现自己的 getSession()方法,来接管创建和管理Session数据的工作。Spring-Session就是通过这样的思路实现的。

    Spring-Session结合Redis实现Session共享。

    四. Spring Session

    1. 传统Session的问题

    我们都知道Session是由Web容器管理的,即一个Session只保存在一台机器上,适合于单体应用。但随着架构的演练,不断的向微服务分布式集群演进,此时传统的Session就不能工作了。如:现在有3台Web服务器,客户端通过Nginx负载均衡技术,来负载到某一台服务器上,用户此次的数据就保存到了这台服务器的Web容器中了。等用户下次请求时,如果被负载到其它机器上,那么就拿不到之前保存的数据了,这时候就需要整个服务器集群共享同一个Session。

    为了解决所有服务器共享一个Session,那么Session就不能单独的保存在自己的Web容器中,而是要保存在一个公共的会话仓库(Session Repository)中,也就是说所有的服务器都要访问这同一个仓库,这样所有服务器的状态便都一致了。Spring Session支持的仓库有Reids、MongoDB、JDBC等。

    2. Spring Session的存储方式

    默认情况下,在Spring Boot中,为Spring Session提供了几种存储方式:

    JDBC

    MongoDB

    Redis

    Hazelcast

    HashMap

    在Spring Session可用的情况下,我们可以选择存储Session的存储类型StoreType。例如,按如下配置将使用JDBC作为后端存储:

    spring.session.store-type=jdbc # 通过设置`store-type`为`none`可以禁用Spring Session

    注:

    出于向后兼容,在Redis可用的情况下,Spring Boot中会默认自动配置及使用Redis来存储Spring Session。

    另外每种存储方式都有特殊设置,例如,对于jdbc存储可自定义要存储的表名:

    spring.session.jdbc.table-name=SESSIONS

    3. Spring Session的优点

    Spring Session是基于Servlet规范实现的一套Session管理框架,主要解决了分布式场景下的Session共享问题。Spring Session最核心的类是SessionRepositoryFilter过滤器,用于包装用户的请求和响应,我们可以在程序中直接替换掉HttpSession,而无需修改一行代码。而且也可以很方便的与Spring Security集成,增加诸如findSessionsByUserName、rememberMe等功能,限制同一个账号可以同时在线的Session数量(如设置成1,即可达到把前一次登录顶掉的效果)等等。

    责任编辑:

    展开全文
  • 一个登录页面,被别的网站用iframe嵌进去后,死活无法登录(只在IE中存在这种情况)。主要是session无法被保存的问题,下面把个人的解决过程分享个大家
  • 首先我们知道,在我们登录网站的时候,点击一个又一个链接,但是用户显示依然存在,这是为什么呢,网站又是如何识别的呢?那怎么来做这个效果呢?接下来用一个例子及原理为大家说明。 原理:session的用法,当我们...

    问题?首先我们知道,在我们登录网站的时候,点击一个又一个链接,但是用户显示依然存在,这是为什么呢,网站又是如何识别的呢?那怎么来做这个效果呢?接下来用一个例子及原理为大家说明。

    原理:session的用法,当我们登陆验证成功后就在session中写一个标记,等点击链接的时候就会一直识别是否有这个标记。


    HttpSession概述及原理探讨
    得到HttpSession对象:
    HttpServletRequest.getSession():根据特殊Cookie(JSESSIONID=HttpSession对象的id,由服务器生成,唯一的)的取值,在服务器的内存中根据id查找这个HttpSession对象,找到了,取出来继续服务;没有找到,创建一个新的HttpSession对象。

    第一步:建立jsp或者html页面

    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
    <%
    String path = request.getContextPath();
    String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
    %>
    
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
      <head>
        <base href="<%=basePath%>">
        
        <title>My JSP 'Login.jsp' starting page</title>
        
    	<meta http-equiv="pragma" content="no-cache">
    	<meta http-equiv="cache-control" content="no-cache">
    	<meta http-equiv="expires" content="0">    
    	<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    	<meta http-equiv="description" content="This is my page">
    	<!--
    	<link rel="stylesheet" type="text/css" href="styles.css">
    	-->
    
      </head>
      <!-- 该函数无法执行的话,可能是没有通知浏览器不要缓存的原因 -->
      <script type="text/javascript">
      	function toreal(){
      		document.location.href="Login.jsp";
      	}
      	
      </script>
      <body>
        <form action="/day08/servlet/LandingServlet" method="post">     <br>
      		用  户 名:<input type="text" name="username">     <br>
      		密      码:<input type="password" name="password">     <br>
      			    <input type="text" name="code">
      			    <img alt="验证码" src="/day08/servlet/ImageServlet"><!-- 内部自动发送请求<span style="white-space:pre">				</span>,加载验证码 -->
        			    <a href="javascript:toreal()">看不清</a><br/>
      			    <input type="submit"  value="提交">
      </form>
      </body>
    </html>
    

    第二步:xml文件

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
      <display-name>day08</display-name>
    
      <servlet>
        <servlet-name>IndexServlet</servlet-name>
        <servlet-class>com.dp.javaweb.login.IndexServlet</servlet-class>
      </servlet>
      <servlet>
        <servlet-name>LandingServlet</servlet-name>
        <servlet-class>com.dp.javaweb.login.LandingServlet</servlet-class>
      </servlet>
      <servlet>
        <servlet-name>LoginoutServlet</servlet-name>
        <servlet-class>com.dp.javaweb.login.LoginoutServlet</servlet-class>
      </servlet>
      <servlet>
        <servlet-name>ImageServlet</servlet-name>
        <servlet-class>com.dp.javaweb.login.ImageServlet</servlet-class>
      </servlet>
    
    
      <servlet-mapping>
        <servlet-name>IndexServlet</servlet-name>
        <url-pattern>/servlet/IndexServlet</url-pattern>
      </servlet-mapping>
      <servlet-mapping>
        <servlet-name>LandingServlet</servlet-name>
        <url-pattern>/servlet/LandingServlet</url-pattern>
      </servlet-mapping>
      <servlet-mapping>
        <servlet-name>LoginoutServlet</servlet-name>
        <url-pattern>/servlet/LoginoutServlet</url-pattern>
      </servlet-mapping>
      <servlet-mapping>
        <servlet-name>ImageServlet</servlet-name>
        <url-pattern>/servlet/ImageServlet</url-pattern>
      </servlet-mapping>
      
      <welcome-file-list>
        <welcome-file>Login.jsp</welcome-file>
      </welcome-file-list>
    </web-app>


    第三步:画图验证码class类

    package com.dp.javaweb.login;
    
    import java.awt.Color;
    import java.awt.Font;
    import java.awt.Graphics;
    import java.awt.image.BufferedImage;
    import java.io.IOException;
    import java.util.Random;
    
    import javax.imageio.ImageIO;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    public class ImageServlet extends HttpServlet {
    
    	public void doGet(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
    		<span style="white-space:pre">		</span>//通知浏览器不要缓存
    				response.setHeader("Expires", "-1");
    				response.setHeader("Cache-Control", "no-cache");
    				response.setHeader("Pragma", "-1");
    				
    				int height=25;
    				int width=120;
    				//得到一个内存图像BufferedImage
    				BufferedImage img=new BufferedImage(width, height, BufferedImage.TYPE_<span style="white-space:pre">				</span>INT_RGB);
    				//得到一个画笔
    				Graphics g=img.getGraphics();
    				//画边框drawRect绘制指定矩形的边框。
    				g.drawRect(0, 0, width, height);
    				//填充颜色
    				g.setColor(Color.RED);
    				g.fillRect(1, 1, width-2, height-2);
    				//画干扰线
    				g.setColor(Color.BLACK);
    				Random r=new Random();
    				for(int i=0;i<20;i++)
    				g.drawLine(r.nextInt(width), r.nextInt(height), r.nextInt(width), r.nextInt(height));
    				//生成随机数字
    				g.setColor(Color.BLUE);
    				g.setFont(new Font("微软雅黑", Font.BOLD|Font.ITALIC, 20));//BOLD加粗,ITALIC斜体
    				int d=15;
    				StringBuffer sb=new StringBuffer();//可变字符串的利用
    				for(int j=0;j<4;j++){
    					String code=r.nextInt(10)+"";
    					sb.append(code);
    					g.drawString(code+"", d, 20);
    					d+=20;
    				}
    				//将验证码输入到session中,用来验证
    				request.getSession().setAttribute("code", sb.toString());
    				//输出打web页面
    				ImageIO.write(img, "jpg", response.getOutputStream());
    	}
    
    	public void doPost(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
    
    		doGet(request, response);
    	}
    
    }
    

    第四步:处理用户密码验证码类(这里就开始利用session的作用,因为痛密码用户一样也在验证码出也写了一个session)

    package com.dp.javaweb.login;
    
    import java.io.IOException;
    import java.io.PrintWriter;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    
    /**
     * 处理用户密码
     *
     */
    public class LandingServlet extends HttpServlet {
    
    	public void doGet(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
    		request.setCharacterEncoding("UTF-8");
    		response.setContentType("text/html;charset=UTF-8");
    		PrintWriter out=response.getWriter();
    		
    		//验证用户和密码
    		String username=request.getParameter("username");
    		String password=request.getParameter("password");
    		String code=request.getParameter("code");
    		//得到session中的session验证码
    		String sessuoncode=(String)request.getSession().getAttribute("code");
    		//验证验证码
    		if(!code.equals(sessuoncode)){
    			out.write("登陆失败,错误的验证码!!<a href='/day08/'>重新登录</a>");
    			return;//不往下执行了
    		}
    		StringBuffer sb=new StringBuffer(password);
    		password=sb.reverse().toString();//reverse()将此字符序列用其反转形式取代
    		if(username.equals(password)){
    			User user=new User();
    			user.setUsername(username);
    			user.setPassword(password);
    			//在把user对象放入session中,有了标记,这点儿很重要。
    			request.getSession().setAttribute("user", user);
    			out.write("登陆成功,2秒后自动返回到主页面!!");
    		}else{
    			out.write("登陆失败,2秒钟后自动返回到主页面!!");
    		}
    		response.setHeader("Refresh","2;URL=/day08/servlet/IndexServlet");
    
    	}
    
    	public void doPost(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
    
    		doGet(request, response);
    	}
    
    }
    

    第五步:验证session是否存在,并处理登陆状态

    package com.dp.javaweb.login;
    
    import java.io.IOException;
    import java.io.PrintWriter;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpSession;
    
    /**
     * 验证session中用户和密码
     *
     */
    public class IndexServlet extends HttpServlet {
    
    	public void doGet(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
    		response.setContentType("text/html;charset=UTF-8");
    		PrintWriter out=response.getWriter();
    		
    		HttpSession session=request.getSession();//创建session对象
    		User user=(User)session.getAttribute("user");//得到标记
    		//session.setMaxInactiveInterval(2);
    		//setMaxInactiveInterval表示2秒内不对session做出操作,自动删除session
    		//一般情况下,不用设置这个函数,因为getMaxInactiveInterval()的session的默认失效为1800毫秒也就是半分钟
    		//System.out.println(session.getMaxInactiveInterval());//打印默认session存在时间
    		if(user==null){
    			out.write("<a href='/day08/'>请登陆</a>");
    		}else{
    			out.write("欢迎您:"+user.getUsername()+"    <a href='/day08/servlet/LoginoutServlet'>注销</a>");
    		}
    		out.write("<hr/>");
     		out.write("主页:");
     		 
    	}
    
    	public void doPost(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
    
    		doGet(request, response);
    	}
    
    }
    

    第六步:注销功能的实现,这个功能主要是将写入session的标记去除掉或者将域中的标记联系中断

    package com.dp.javaweb.login;
    
    import java.io.IOException;
    import java.io.PrintWriter;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    //去掉session中的登陆标记,也就是用于注销
    public class LoginoutServlet extends HttpServlet {
    
    	public void doGet(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
    		response.setContentType("text/html;charset=UTF-8");
    		request.setCharacterEncoding("UTF-8");
    		PrintWriter out=response.getWriter();
    		request.getSession().removeAttribute("user");//删除了域中绑定的对象
    //		request.getSession().invalidate();//这是直接销毁session,可任选一种
    		out.write("注销成功,2秒后自动转入主页。");
    		response.setHeader("Refresh", "2;URL=/day08/servlet/IndexServlet");
    	}
    
    	public void doPost(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
    
    		doGet(request, response);
    	}
    
    }
    

    第七步:封装用户密码的Bean类

    package com.dp.javaweb.login;
    
    public class User {
    	private String username;
    	private String password;
    	public String getUsername() {
    		return username;
    	}
    	public void setUsername(String username) {
    		this.username = username;
    	}
    	public String getPassword() {
    		return password;
    	}
    	public void setPassword(String password) {
    		this.password = password;
    	}
    	
    	
    }
    

    结果显示:

            

    第一种情况:验证码错误

           

    第二种情况:用户密码错误

           

    第三种情况:登陆成功后

                        

    最后的注销就不用我说了吧!就是去掉session的标记。


    注意:session.setMaxInactiveInterval(30 * 60);//单位秒,这是设置网页中session在缓存中的存在时间
       如果不设置的话,session,默认过期时间为30分钟也就是1800秒,

        session时间的另外一种设置方式,在另一边博客上写得有喔。

    展开全文
  • Session是怎么实现的?存储在哪里?

    万次阅读 多人点赞 2017-06-30 21:20:00
    为什么有session 如何实现session的共享 SESSION 的数据保存在哪里呢 PHP中的session存储 Java中的session存储 博主注前言 文章内容转载或摘录自,如下文章。最后将在文末【博主注】这一部分,指出一些需要注意的...

    目录

    前言

      文章内容转载或摘录自,如下文章。最后将在文末【博主注】这一部分,指出一些需要注意的地方。

    为什么有session?

      首先大家知道,http协议是无状态的,即你连续访问某个网页100次和访问1次对服务器来说是没有区别对待的,因为它记不住你。
      那么,在一些场合,确实需要服务器记住当前用户怎么办?比如用户登录邮箱后,接下来要收邮件、写邮件,总不能每次操作都让用户输入用户名和密码吧,为了解决这个问题,session的方案就被提了出来,事实上它并不是什么新技术,而且也不能脱离http协议以及任何现有的web技术。
      原理很简单,假设你访问网页时就像逛澡堂,第一次进去你是没有钥匙的,这个时候你交了钱服务台就分配一把钥匙给你,你走到哪里都要带上,因为这是你身份的唯一标识,接下来你用这把钥匙可以去打开一个专有的储物柜存储你的衣物,游完泳,你再用钥匙去打开柜子拿出衣物,最后离开游泳池时,把钥匙归还,你的这次游泳的过程就是一次session,或者叫做会话,在这个例子中,钥匙就是session的key,而储物柜可以理解为存储用户会话信息的介质。
      那么在web server中如何实现session呢?想必看了上面的例子你会很容易理解,主要是解决两个问题,一个是钥匙的问题,一个是存储用户信息的问题。对于第一个问题,即什么东西可以让你每次请求都会自动带到服务器呢?如果你比较了解http协议,那么答案一目了然,就是cookie,如果你想为用户建立一次会话,可以在用户授权成功时给他一个cookie,叫做会话id,它当然是唯一的,比如PHP就会为建立会话的用户默认set一个名为phpsessid,值看起来为一个随机字符串的cookie,如果下次发现用户带了这个cookie,服务器就知道,哎呀,刚刚这位顾客来了。
      剩下的是解决第二个问题,即如何存储用户的信息,服务器知道会话id为abc的用户来了,那abc想存储自己的私人信息,比如购物车信息,如何处理?这个时候可以用内存、也可以用文件,也可以用数据库了,但有个要求是,数据需要用用户的会话id即可取到,比如php就默认会把会话id为abc的用户会话数据存储到/tmp/phpsess_abc【1】的文件里面,每次读取都要反序列化程序可以理解的数据,写的时候又需要序列化为持久的数据格式。

    如何实现session的共享?

      首先我们应该明白,为什么要实现共享,如果你的网站是存放在一个机器上,那么是不存在这个问题的,因为会话数据就在这台机器,但是如果你使用了负载均衡把请求分发到不同的机器呢?这个时候会话id在客户端是没有问题的,但是如果用户的两次请求到了两台不同的机器,而它的session数据可能存在其中一台机器,这个时候就会出现取不到session数据的情况,于是session的共享就成了一个问题。
      事实上,各种web框架早已考虑到这个问题,比如asp.NET,是支持通过配置文件修改session的存储介质为sql server的,所有机器的会话数据都从同一个数据库读,就不会存在不一致的问题;php支持把会话数据存储到某台memcache服务器,你也可以手工把session文件存放的目录改为nfs网络文件系统,从而实现文件的跨机器共享。
      还有一个简单的办法可以用于会话信息不会频繁变更的情况,在机器a设置用户会话的时候,把会话数据post到机器b的一个cgi,机器b的cgi把会话数据存下来,这样机器a和b都会有同一份session数据的拷贝。【2】  

    SESSION 的数据保存在哪里呢?

    PHP中的session存储

      SESSION 的数据保存在哪里呢?
      当然是在服务器端,但不是保存在内存中,而是保存在文件或数据库中。
       默认情况下,PHP.ini 中设置的 SESSION 保存方式是 files(session.save_handler = files),即使用读写文件的方式保存 SESSION 数据,而 SESSION 文件保存的目录由 session.save_path 指定,文件名以 sess_ 为前缀,后跟 SESSION ID,如:sess_c72665af28a8b14c0fe11afe3b59b51b。文件中的数据即是序列化之后的 SESSION 数据了。
       如果访问量大,可能产生的 SESSION 文件会比较多,这时可以设置分级目录进行 SESSION 文件的保存,效率会提高很多,设置方法为:session.save_path="N;/save_path",N 为分级的级数,save_path 为开始目录。
       当写入 SESSION 数据的时候,php 会获取到客户端的 SESSION_ID,然后根据这个 SESSION ID 到指定的 SESSION 文件保存目录中找到相应的 SESSION 文件,不存在则创建之,最后将数据序列化之后写入文件【3】。读取 SESSION 数据是也是类似的操作流程,对读出来的数据需要进行解序列化,生成相应的 SESSION 变量。

    Java中的session存储

      sessionid是一个会话的key,浏览器第一次访问服务器会在服务器端生成一个session,有一个sessionid和它对应。tomcat生成的sessionid叫做jsessionid。
      session在访问tomcat服务器HttpServletRequest的getSession(true)的时候创建,tomcat的ManagerBase类提供创建sessionid的方法:随机数+时间+jvmid。
      存储在服务器的内存中,tomcat的StandardManager类将session存储在内存中,也可以持久化到file,数据库,memcache,redis等。客户端只保存sessionid到cookie中,而不会保存session,session销毁只能通过invalidate或超时,关掉浏览器并不会关闭session。


      那么Session在何时创建呢?当然还是在服务器端程序运行的过程中创建的,不同语言实现的应用程序有不同创建Session的方法,而在Java中是通过调用HttpServletRequest的getSession方法(使用true作为参数)创建的。【4】在创建了Session的同时,服务器会为该Session生成唯一的Session id,而这个Session id在随后的请求中会被用来重新获得已经创建的Session;在Session被创建之后,就可以调用Session相关的方法往Session中增加内容了,而这些内容只会保存在服务器中,发到客户端的只有Session id;当客户端再次发送请求的时候,会将这个Session id带上,服务器接受到请求之后就会依据Session id找到相应的Session,从而再次使用之。


      创建:sessionid第一次产生是在直到某server端程序调用 HttpServletRequest.getSession(true)这样的语句时才被创建。
      删除:超时;程序调用HttpSession.invalidate();程序关闭。
      session存放在哪里:服务器端的内存中。【5】不过session可以通过特殊的方式做持久化管理(memcache,redis)。
      session的id是从哪里来的,sessionID是如何使用的:当客户端第一次请求session对象时候,服务器会为客户端创建一个session,并将通过特殊算法算出一个session的ID,用来标识该session对象。
      session会因为浏览器的关闭而删除吗?不会,session只会通过上面提到的方式去关闭。【6】

    博主注

    【1】这里需要说明下。博主在Windows下wamp中查看到wamp安装目录下有tmp目录,其中session数据保存的文件以”sess_”作为前缀命名。在CentOS中nginx+php-fpm环境中,配置session的保存路径(在php.ini中配置session.save_path的值,注意这个路径需要Web服务器进程所属用户有权操作-读写操作)后,保存的session文件同样以“sess_”作为前缀命名。
    【2】除了上述提及的方法外,解决session共享问题还有这样一种方式:(实质上并不是通过session的共享来解决的)这里以nginx为例,将用户请求分发到了不同机器上,那么我们只需要固定,同一用户请求分发到同一机器上进行处理,即这一次用户来请求服务器了,那么下一次它再来的时候,同样也请求也被分发到与上一次相同的服务器。这样就确保了同一用户不会因为请求分发到不同机器上而获取不到session数据的问题了。
    【3】后台服务端可以将数据保存在session中,对于php而言,是将数据序列化后保存在文件中,内容如下:

    USER|a:5:{s:7:"user_id";s:6:"512071";s:8:"username";s:18:"未命名的昵称";s:5:"phone";s:11:"18888888888";s:9:"last_time";s:19:"2017-06-30 15:45:55";s:6:"is_vip";s:1:"0";}noLoginUser|a:2:{s:10:"session_id";s:40:"captcha_81cd8166e5a84a56605c5903466416da";s:11:"verify_code";s:4:"9626";}

    【4】从浏览器打开访问了某一个网站,关闭浏览器。这样的操作我们算一次“会话”。所以大部分就会认为用户访问了网站就会产生session ID。实际上不然。例如:在Java中我们需要调用HttpServletRequest的getSession方法创建session。而在PHP中需要session_start()一下,服务器才会将存有session ID的cookie回传回去。否则不会有什么session产生。
    【5】“session存放在哪里:服务器端的内存中。”指的是Tomcat保存session的方式。对于PHP而言是保存在文件中。上述有提及。
    【6】session不会因为浏览器的关闭而删除。但是存有session ID的cookie的默认过期时间是会话级别。也就是用户关闭了浏览器,那么存储在客户端的session ID便会丢失,但是存储在服务器端的session数据并不会被立即删除。从客户端即浏览器看来,好像session被删除了一样(因为我们丢失了session ID,找不到原来的session数据了)。

    展开全文
  • 参考自:http://www.cnblogs.com/qulinke/articles/6003049.htmlhttps://segmentfault.com/q/1010000005788476... 让所有域名对应的服务器访问的Session的数据的位置必须一致下面重点讲讲实现,Session共享相对...
  • 前端网络基础 - Session

    千次阅读 2022-03-09 18:53:44
    所以服务器端也需要对session考虑以上管理行为 session保存在session如何获取? session何时清除? 服务器端既可以将session缓存在内存中,也可以将session持久化在硬盘中。但是缓存在内存中的session的生命...
  • Session是在服务器端保持会话数据的一种方法(通常用于pc端网站保持登录状态,手机端通常会使用token方式实现),存储在服务端。 Cookie是在客户端保持用户数据,存储位置是客户端(浏览器或者手机端)。   二、...
  • Session原理

    万次阅读 多人点赞 2019-06-18 08:35:21
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~...开发工具与关键技术:Java,HTTP协议,session原理 撰写时间:2019-06-17 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~...
  • 基于 session 的登陆

    千次阅读 2021-12-23 16:03:29
    常见的方法是使用 session 机制,也就是我们现在大多数时候使用的方式。 常见的 session 工作模型是这样的 session 机制 用户在浏览器登陆之后,服务端为用户生成唯一的 session id,存储在服务端的存储服务(例如 ...
  • Flask操作session

    千次阅读 2019-06-27 20:37:29
    from flask import Flask,session import os app = Flask(__name__) app.config['SECRET_KEY'] = os.urandom(24) # 必须要设置否则报错,RuntimeError:会话不可用,因为没有设置密钥。将应用程序上的secret_key...
  • Spring Session处理Session丢失问题

    千次阅读 2020-01-07 21:18:25
    URL 重写二、Session机制存在的问题与解决方案1. 存在的问题2. 解决方案三、Spring Session1. 简介2. SSM中实现(1)添加Spring Session相关依赖2. 配置springSessionRepositoryFilter过滤器3. 一、会话跟踪技术 ...
  • Session伪造记录

    2021-09-05 21:41:06
    简单的说,当你登陆一个网站的时候,如果web服务器端使用的是session,那么所有的数据都保存在服务器上,客户端每次请求服务器的时候会发送当前会话sessionid,服务器根据当前sessionid判断相应的用户数据标志,以...
  • 彻底讲清Web开发的Cookie、Session机制

    千次阅读 多人点赞 2021-07-15 15:15:22
    会话(Session)跟踪是Web程序中常用的技术,用来跟踪用户的整个会话 常用的会话跟踪技术是Cookie与Session。 Cookie通过在客户端记录信息确定用户身份 Session通过在服务器端记录信息确定用户身份 本文将系统地讲述...
  • 面试考点:session和cookie

    千次阅读 多人点赞 2022-03-25 16:07:49
    文章目录一、关于 cookie 的前言概括二、session 工作原理三、常用的方法3.1 getSession()3.2 getAttribute()和setAttribute()四、关系总结图五、实操:实现登录功能并计算访问页面的次数5.1 登录页面实现(login....
  • sessionsessionID以及cookie的关系

    千次阅读 2019-04-16 12:32:10
    session存在于服务器中,需要有httpservletrequest的request对象调用getsession方法来创建session对象, request.getSession(true) 调用session,.为true时表示可以创建一个session。eg: HttpSession session = ...
  • session

    千次阅读 2018-08-06 20:32:15
     在WEB开发中,服务器可以为每个用户浏览器创建一个会话对象(session对象),注意:一个浏览器独占一个session对象(默认情况下)。因此,在需要保存用户数据时,服务器程序可以把用户数据写到用户浏览器独占的...
  • Session 会话

    千次阅读 2017-09-04 18:10:57
    HTTP 是一种”无状态”协议,所以客户端...维持Session的三种方式 Cookies 一个 Web 服务器可以分配一个唯一的 session 会话 ID 作为每个 Web 客户端的 cookie,对于客户端的后续请求可以使用接收到的 cookie 来识别。
  • 借csrf理解session原理

    万次阅读 2021-04-16 22:31:28
    xss利用站点内的信任用户,csrf通过伪装成受信任用户请求受信任的网站,即攻击者利用目标用户的身份,以目标用户的名义执行某些非法操作 攻击两个重点: 目标用户已经登陆了网站,能够执行网站的功能 目标用户访问...
  • 问题:session什么时候被创建? 一个常见的错误是以为 session 在有客户端访问时就被创建,然而事实是直到某 server 端程序(如 Servlet )调用HttpServletRequest.getSession(true)这样的语句时才会被创建。 在浏览...
  • 我们上一篇文章的入门案例就属于这种应用场景,只不过在实际开发的过程中,我们如果存在了 tomcat 集群,那么肯定会使用 nginx 进行负载均衡,那么这种情况下我们该如何处理。 1. 思路 我们将上一个阶段的 p2p 项目...
  • Session详解

    千次阅读 热门讨论 2018-10-18 16:59:30
    四大域对象 1.概念     称为实体类实例,对应... (1)Session域     A: 产生: 第一次调用 request.getSession()时产生     B:作用: 存储访问该程序的一个用户的信息     C: 生命周期: 第一次调用re...
  • 这样,当用户在应用程序的 Web 页之间跳转时,存储在 Session 对象中的变量将不会丢失,而是在整个用户会话中一直存在下去。当用户请求来自应用程序的 Web 页时,如果该用户还没有会话,则 Web 服务器将自动创建一个...
  • 记一次Session跨域问题

    千次阅读 2022-03-01 10:16:58
    背景:网站域名:aa.abc.com,客户有需求,需要定制专属域名,如:kehu....后台服务也做了处理,如果登录用户判断有专属域名,则直接重定向到专属域名上,否则使用网站域名。逻辑很简单,流程如下,其他跳转页面的接口
  • 做网站难免要面对安全性的问题,诸如sql注入拉,cookie冒名拉,等等,sql注入算是老生常谈,翻翻旧账有不少优秀的帖子在说明这个问题,所以我们来说说Session冒名顶替的风险以及应对的办法。 首先要说Session...
  •  多个用户共享的应用级别的作用域,在服务器端,相比前两者,这个存在时间是最长的,只有当关闭服务器的时候才死亡!所以他可以活很长时间。  Application用于保存所有用户的公共的数据信息,如果使用Application...
  • Nginx——Session共享

    千次阅读 2021-03-08 16:30:41
    Session共享
  • session详解

    千次阅读 2018-07-30 18:55:43
    如:从web应用的用户看来,他打开浏览器访问一个电子商务网站,登录、并完成购物直到关闭浏览器,这是一个会话。而在web应用开发者看来,用户登录时我需要创建数据结构以存储用户的登录信息,这个结构也叫作session...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 133,595
精华内容 53,438
关键字:

网站session存在哪