精华内容
参与话题
问答
  • 【JavaWeb】Redis存储Session方案

    千次阅读 2016-09-03 14:41:46
    所有支持Servlet规范的容器都自带session管理,于是大多数人都使用HttpSession接口存放状态信息。事实上, servlet的session会使得应用服务器水平扩展变的非常困难。 使用Servlet Session时的妥协方案 Session ...

    所有支持Servlet规范的容器都自带session管理,于是大多数人都使用HttpSession接口存放状态信息。事实上, servlet的session会使得应用服务器水平扩展变的非常困难。

    使用Servlet Session时的妥协方案

    Session Replication

    这无疑是一种浪费内存的方法,对于5台左右的集群还可以忍受,如果你需要几十甚至上百台集群,这就完全不可行。

    Session Sticky

    该方案虽然可以避免上面的问题,但是这完全背离了负载均衡的初衷。假如有A, B服务器,A处理session为1 ~ 5的请求,B处理session为6 ~ 10的请求,如果某个时间段内,有1 ~ 5 session的用户访问需求非常高,而6 ~ 10 session的用户不怎么访问,这样就会导致A服务器负载过高而B却十分清闲,此时负载均衡就失去了意义。

    使用Redis进行Session存储

    在应用编写时应该完全弃用HttpSession接口,而是将需要保存的状态信息放到Redis中。

    生成session id

    当用户登陆时,服务器生成一个全局唯一的字符串SESSION:日期:20位随机字符串做为redis中hash数据结构的key名,然后将该标识做为cookie返回给客户端。 之后该用户的后续请求都会带上此cookie, 我们编写一个filter, 其作用为读取请求中的标识,从redis中取出该标识对应的数据,然后放到HttpServletRequest对象中以供后续使用。

    session过期

    使用redis自带的过期功能为session id设置过期时间,轻松实现session过期。

    session追踪

    我们可以将每个用户的session id记录下来,如保存到数据库中,或者依然放在redis里,这样就可以查到某个注册用户所有session id, 轻松实现踢出登陆功能。

    session更新

    通过AOP, 在每个请求完后之后,检查在请求处理过程中有没有更新session信息,如果有则将新数据刷新到Redis中。

    将session转移到redis中后,只要做好redis的运维工作,我们的应用服务器已经是完全无状态的了,水平扩展时只需要添加机器而不需要改动任何一行代码。

    展开全文
  • Cookie与Session的介绍与区别

    千次阅读 2016-04-20 09:50:12
    本文分别对Cookie与Session做一个介绍和总结,并分别对两个知识点进行对比分析,让大家对Cookie和Session有一个更深入的了解,并对自己的开发工作中灵活运用带来启示。 一、Cookie机制  Cookies...

     本文分别对Cookie与Session做一个介绍和总结,并分别对两个知识点进行对比分析,让大家对Cookie和Session有一个更深入的了解,并对自己的开发工作中灵活运用带来启示。



    一、Cookie机制

         Cookies是服务器在本地机器上存储的小段文本并随每一个请求发送至同一个服务器。IETF RFC 2965 HTTP State Management Mechanism 是通用cookie规范。网络服务器用HTTP头向客户端发送Cookies,在客户终端,浏览器解析这些Cookies并将它们保存为一个本地文件,它会自动将同一服务器的任何请求缚上这些Cookies。

         具体来说Cookie机制采用的是在客户端保持状态的方案。它是在用户端的会话状态的存贮机制,他需要用户打开客户端的Cookie支持。Cookie的作用就是为了解决HTTP协议无状态的缺陷所作的努力。(HTTP无状态协议是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。)

         正统的Cookie分发是通过扩展HTTP协议来实现的,服务器通过在HTTP的响应头中加上一行特殊的指示以提示浏览器按照指示生成相应的Cookie。然而纯粹的客户端脚本如JavaScript也可以生成Cookie。而Cookie的使用是由浏览器按照一定的原则在后台自动发送给服务器的。浏览器检查所有存储的Cookie,如果某个Cookie所声明的作用范围大于等于将要请求的资源所在的位置,则把该Cookie附在请求资源的HTTP请求头上发送给服务器。

         Cookie的内容主要包括:名字,值,过期时间,路径和域。路径与域一起构成cookie的作用范围。若不设置过期时间,则表示这个Cookie的生命期为浏览器会话期间,关闭浏览器窗口,cookie就消失。这种生命期为浏览器会话期的Cookie被称为会话Cookie。会话Cookie一般不存储在硬盘上而是保存在内存里,当然这种行为并不是规范规定的。若设置了过期时间,浏览器就会把Cookie保存到硬盘上,关闭后再次打开浏览器,这些Cookie仍然有效直到超过设定的过期时间。存储在硬盘上的Cookie可以在不同的浏览器进程间共享,比如两个IE窗口。而对于保存在内存里的cookie,不同的浏览器有不同的处理方式。

         而Session机制采用的是一种在服务器端保持状态的解决方案。同时我们也看到,由于采用服务器端保持状态的方案在客户端也需要保存一个标识,所以Session机制可能需要借助于Cookie机制来达到保存标识的目的。而Session提供了方便管理全局变量的方式。

         Session是针对每一个用户的,变量的值保存在服务器上,用一个SessionID来区分是哪个用户Session变量,这个值是通过用户的浏览器在访问的时候返回给服务器,当客户禁用Cookie时,这个值也可能设置为由get来返回给服务器。

         就安全性来说:当你访问一个使用Session 的站点,同时在自己机子上建立一个Cookie,建议在服务器端的Session机制更安全些,因为它不会任意读取客户存储的信息。

    二、Session机制

         Session机制是一种服务器端的机制,服务器使用一种类似于散列表的结构(也可能就是使用散列表)来保存信息。

         当程序需要为某个客户端的请求创建一个Session时,服务器首先检查这个客户端的请求里是否已包含了一个Session标识(称为Session id),如果已包含则说明以前已经为此客户端创建过Session,服务器就按照Session id把这个session检索出来使用,如果客户端请求不包含Session id,则为此客户端创建一个Session并且生成一个与此Session相关联的Session id,Session id的值应该是一个既不会重复,又不容易被找到规律以仿造的字符串,这个session id将被在本次响应中返回给客户端

    保存。

         保存这个Session id的方式可以采用Cookie,这样在交互过程中浏览器可以自动的按照规则把这个标识发挥给服务器。一般这个Cookie的名字都是类似于SEEESIONID。但Cookie可以被人为的禁止,则必须有其他机制以便在Cookie被禁止时仍然能够把Session id传递回服务器。

         经常使用的一种技术叫URL重写,就是把Session id直接附加在URL路径的后面。还有一种技术叫做表单隐藏字段。就是服务器会自动修改表单,添加一个隐藏字段,以便在表单提交时能够把Session id传递回服务器。

         Cookie与Session都能够进行会话跟踪,但是完成的原理不太一样。普通状况下二者均能够满足需求,但有时候不能够运用Cookie,有时候不能够运用Session。下面经过比拟阐明二者的特性以及适用的场所。

     

    三、Cookie与Session的区别:

         ①存取方式的不同(Cookie只能保存ASCII,Session可以存任意数据类型)

         Cookie中只能保管ASCII字符串,假如需求存取Unicode字符或者二进制数据,需求先进行编码。Cookie中也不能直接存取Java对象。若要存储略微复杂的信息,运用Cookie是比拟艰难的。

         而Session中能够存取任何类型的数据,包括而不限于String、Integer、List、Map等。Session中也能够直接保管Java Bean乃至任何Java类,对象等,运用起来十分便当。能够把Session看做是一个Java容器类。


         ②隐私策略的不同(Cookie存储在客户端阅读器中,Session存储在服务器上)

         Cookie存储在客户端阅读器中,对客户端是可见的,客户端的一些程序可能会窥探、复制以至修正Cookie中的内容。而Session存储在服务器上,对客户端是透明的,不存在敏感信息泄露的风险。

         假如选用Cookie,比较好的方法是,敏感的信息如账号密码等尽量不要写到Cookie中。最好是像Google、Baidu那样将Cookie信息加密,提交到服务器后再进行解密,保证Cookie中的信息只要本人能读得懂。而假如选择Session就省事多了,反正是放在服务器上,Session里任何隐私都能够有效的保护。


         ③有效期不同(Cookie可设长时间,Session关闭浏览器就失效)

         使用过Google的人都晓得,假如登录过Google,则Google的登录信息长期有效。用户不用每次访问都重新登录,Google

    会持久地记载该用户的登录信息。要到达这种效果,运用Cookie会是比较好的选择。只需要设置Cookie的过期时间属性为一个

    很大很大的数字。

         由于Session依赖于名为JSESSIONID的Cookie,而Cookie JSESSIONID的过期时间默许为–1,只需关闭了阅读器该

    Session就会失效,因而Session不能完成信息永世有效的效果。运用URL地址重写也不能完成。而且假如设置Session的

    超时时间过长,服务器累计的Session就会越多,越容易招致内存溢出。(这时使用Local Storage本地存储)


         ④服务器压力不同(Cookie压力小于Session)

         Session是保管在服务器端,每个用户都会产生一个Session。假如并发访问的用户十分多,会产生十分多的Session,

    耗费大量的内存。因而像Google、Baidu、Sina这样并发访问量极高的网站,是不太可能运用Session来追踪客户会话的。

         而Cookie保管在客户端,不占用服务器资源。假如并发阅读的用户十分多,Cookie是很好的选择。关于Google、Baidu

    、Sina来说,Cookie或许是唯一的选择。


         ⑤存储大小不同

         单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。


         ⑤浏览器支持的不同

         Cookie是需要客户端浏览器支持的。假如客户端禁用了Cookie,或者不支持Cookie,则会话跟踪会失效。关于WAP上的

    应用,常规的Cookie就派不上用场了。

         假如客户端浏览器不支持Cookie,需要运用Session以及URL地址重写。需要注意的是一切的用到Session程序的URL都

    要进行URL地址重写,否则Session会话跟踪还会失效。关于WAP应用来说,Session+URL地址重写或许是它唯一的选择。

         假如客户端支持Cookie,则Cookie既能够设为本浏览器窗口以及子窗口内有效(把过期时间设为–1),也能够设为一切

    阅读器窗口内有效(把过期时间设为某个大于0的整数)。但Session只能在本阅读器窗口以及其子窗口内有效。假如两个

    浏览器窗口互不相干,它们将运用两个不同的Session。(IE8下不同窗口Session相干)


         ⑥跨域支持上的不同

         Cookie支持跨域名访问,例如将domain属性设置为“.biaodianfu.com”,则以“.biaodianfu.com”为后缀的一切域名均能够

    访问该Cookie。跨域名Cookie如今被普遍用在网络中,例如Google、Baidu、Sina等。而Session则不会支持跨域名访问

    。Session仅在他所在的域名内有效。


    四、总结

         仅运用Cookie或者仅运用Session可能完成不了理想的效果。这时应该尝试一下同时运用Cookie与Session。Cookie与

    Session的搭配运用在实践项目中会完成很多意想不到的效果。

         将登陆信息等重要信息存放为Session

         其他信息如果需要保留,可以放在Cookie中

    展开全文
  • Session的底层实现原理

    千次阅读 2019-05-28 11:21:57
    Session实现原理 客户对向服务器端发送请求后,Session 创建在服务器端,返回Sessionid给客户端浏览器保存在本地, 当下次发送请求的时候,在请求头中传递sessionId获取对应的从服务器上获取对应的Sesison Session...
    Session实现原理
    客户对向服务器端发送请求后,Session 创建在服务器端,返回Sessionid给客户端浏览器保存在本地,
    当下次发送请求的时候,在请求头中传递sessionId获取对应的从服务器上获取对应的Sesison
    
    Session常见问题
    Session 保证在那里?
    答案:存放在服务器上
    关闭浏览器Session会失效吗
    答案:不会消失
    

     

    我们开始分析SESSION的一个原理,这是要重点的去给大家讲的,SESSION的原理,我们在讲SESSION原理的时候要快一点,
    
    localhost:8080/createSession?nameValue=zhangsan 
    
    http://localhost:8080/getSession
    
    SESSION常见的问题,浏览器关闭了SESSION,SESSION会失效吗,这个是为空的,既然是为空的,在这里我们做一件事,
    
    localhost:8080/createSession?nameValue=leon644,这个时候我们是不是可以把值存放进去了,这个时候我们再查一下,
    
    http://localhost:8080/getSession, 8080-leon644,是不是查得到,这个是属于一个非常基础的知识,浏览器关闭session
    
    会失效吗,这是第一个问题,第二个问题是SESSION存放在哪里,有没有人能告诉我答案的,SESSION肯定是存放在服务器端上的,
    
    浏览器关闭SESSION,SESSION会失效吗,肯定不会失效的,为什么呢,这是我要重点去讲的,在这个地方我去给大家画一个图,
    
    画一个什么图呢,在这个地方我们写一下,叫做客户端,我们举一反三,然后把它去copy一遍,是不是叫做服务器端的,这个地方我们
    
    叫做服务器端,你们要记住,我们发起http请求的话,客户端和服务器端要进行通信的时候,在这个时候大家一定要思考一下,
    
    走的是请求,英文叫做request,那么举一反三,如果服务器端响应给客户端的时候,这个时候我们叫做response,这个你们肯定都知道,
    
    response的英文怎么说,我们叫做响应,响应的过程我们叫做response,那么这个地方你们肯定就知道了,本身来说一个HTTP通信的话,
    
    http通讯本身就是基于请求和响应的过程,既然他基于请求和响应的话,这个时候客户端我们可以理解为浏览器,这个地方大家去看,
    
    你们看代码
    
    Cookie: JSESSIONID=66115D0AA6ACFCF82AA61999799F571A
    
    存入Session  sessionid:信息66115D0AA6ACFCF82AA61999799F571A,nameValue:zhangsan,serverPort:8080
    
    这个时候本地是会把SESSIONID保存起来,这表示什么意思呢,http://localhost:8080/createSession?nameValue=zhangsan
    
    这是第一次请求,也就是什么意思,也就是客户端向服务器端发起createSession请求的时候,创建session,返回sessionId
    
    打开开发者工具里面,当你再去查询的时候,客户端是不是会读取到本地的sessionId,存放到请求头里面去,是不是能够查到
    
    这个值,在请求头里面是不是有sessionId,客户端它会读取到本地的sessionId,然后存放到请求头里面去,他这边是不是就查
    
    对应的结果,你们有没有发现一个问题,为什么响应头里面没有显示全,createSession的时候响应头里面为什么没有sessionId,
    
    但是请求头里面有sessionId,这是什么原因,你们不觉得不对劲吗,客户端发起一个createSession请求的时候,通过响应头
    
    把sessionId响应给客户端,响应头里面没有返回sessionId给客户端,但是请求头里面有,这是什么原因,是因为你第一次
    
    创建完了之后,
    
    Set-Cookie: JSESSIONID=A8E197E167C7750BB9D19D1B8F420B5B; Path=/; HttpOnly
    
    Cookie: JSESSIONID=66115D0AA6ACFCF82AA61999799F571A
    
    读取缓存中的,在这边你们把缓存全部清掉看,因为它已经有了,清除缓存,他是不是会把本地的sessionId全部给清除掉,
    
    这个之后,是不是返回来sessionId看到没有,
    
    Set-Cookie: JSESSIONID=A8E197E167C7750BB9D19D1B8F420B5B; Path=/; HttpOnly
    
    是不是就是这个sessionId,首先客户端向服务端发起请求的时候,它会返回一个sessionId给客户端,通过响应头返回给客户端的,
    
    那么浏览器捕获到响应头,获取到对应的sessionId的时候,保存在本地的,保存在本地之后,当你在这边getSession的时候,
    
    他是不是直接读取本地的sessionId,存放在请求头里面,是不是这样的,是不是可以查到里面的信息了,是不是这样的,
    
    当我第二次重新加载的时候,他是不是没有返回sessionId,因为本地cookie已经缓存了sessionId了,我可以复用的,
    
    这就是session的整个原理过程,比较简单,那么这边我要总结一下,你们知道session肯定是存在服务器端的,是存放在
    
    客户端的,只是sessionId是存放在客户端进行保存的
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>com.learn</groupId>
      <artifactId>demo</artifactId>
    	<version>0.0.1-SNAPSHOT</version>
    	<parent>
    		<groupId>org.springframework.boot</groupId>
    		<artifactId>spring-boot-starter-parent</artifactId>
    		<version>2.0.0.RELEASE</version>
    		<relativePath /> <!-- lookup parent from repository -->
    	</parent>
    	<properties>
    		<weixin-java-mp.version>2.8.0</weixin-java-mp.version>
    		<maven.compiler.source>1.8</maven.compiler.source>
    		<maven.compiler.target>1.8</maven.compiler.target>
    		<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
    		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    		<project.build.locales>zh_CN</project.build.locales>
    	</properties>
    
    	<dependencies>
    		<dependency>
    			<groupId>org.projectlombok</groupId>
    			<artifactId>lombok</artifactId>
    		</dependency>
    		<dependency>
    			<groupId>org.springframework.boot</groupId>
    			<artifactId>spring-boot-starter-web</artifactId>
    			<!-- <exclusions> <exclusion> <groupId>com.fasterxml.jackson.core</groupId> 
    				<artifactId>jackson-databind</artifactId> </exclusion> </exclusions> -->
    		</dependency>
    		<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
    		<dependency>
    			<groupId>com.alibaba</groupId>
    			<artifactId>fastjson</artifactId>
    			<version>1.2.47</version>
    		</dependency>
    		<!-- Testing Dependencies -->
    		<dependency>
    			<groupId>org.springframework.boot</groupId>
    			<artifactId>spring-boot-starter-test</artifactId>
    			<scope>test</scope>
    		</dependency>
    		<!-- <dependency>
    			<groupId>org.springframework.boot</groupId>
    			<artifactId>spring-boot-starter-data-redis</artifactId>
    		</dependency> -->
    		<!--spring session 与redis应用基本环境配置,需要开启redis后才可以使用,不然启动Spring boot会报错 -->
    		<!-- <dependency>
    			<groupId>org.springframework.session</groupId>
    			<artifactId>spring-session-data-redis</artifactId>
    		</dependency> -->
    		<dependency>
    			<groupId>org.apache.commons</groupId>
    			<artifactId>commons-pool2</artifactId>
    		</dependency>
    		<!-- <dependency>
    			<groupId>redis.clients</groupId>
    			<artifactId>jedis</artifactId>
    		</dependency> -->
    
    	</dependencies>
    	<build>
    		<plugins>
    			<plugin>
    				<groupId>org.apache.maven.plugins</groupId>
    				<artifactId>maven-compiler-plugin</artifactId>
    				<configuration>
    					<source>1.8</source>
    					<target>1.8</target>
    				</configuration>
    			</plugin>
    			<plugin>
    				<groupId>org.springframework.boot</groupId>
    				<artifactId>spring-boot-maven-plugin</artifactId>
    				<configuration>
    					<maimClass>com.learn.WxMpApplication</maimClass>
    				</configuration>
    				<executions>
    					<execution>
    						<goals>
    							<goal>repackage</goal>
    						</goals>
    					</execution>
    				</executions>
    
    			</plugin>
    		</plugins>
    	</build>
    
    </project>
    server:
      port: 8080
    spring:
      redis:
        database: 0
        host: 59.110.138.145
        port: 6666
        password: 1234
        jedis:
          pool:
            max-active: 8
            max-wait: -1
            max-idle: 8
            min-idle: 0
        timeout: 10000
    redis:
     hostname: 59.110.138.145
     port: 6666
     password: 1234
    
    package com.learn.controller;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpSession;
    
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * 
     * @author Leon.Sun
     *
     */
    @SpringBootApplication
    @RestController
    public class TestSessionController {
    	/**
    	 * 这表示端口号
    	 * 这是读取配置文件里面的
    	 * 为什么这么做的目的
    	 * 目的是为了区分服务器不同的节点
    	 * 
    	 * 
    	 * @return
    	 */
    	@Value("${server.port}")
    	private String serverPort;
    
    	@RequestMapping("/")
    	public String index() {
    		return serverPort;
    	}
    
    	// 创建session 会话
    	/**
    	 * 这段代码表示什么意思呢
    	 * 表示他会去创建一个SESSION
    	 * 就是通过拿到request对象
    	 * 
    	 * 比如现在客户端发起一个createSession请求
    	 * 如果他一旦发起createSession请求的时候
    	 * 那么这个时候你们去看一段代码
    	 * 看一段什么代码呢
    	 * 
    	 * 
    	 * 
    	 * @param request
    	 * @param nameValue
    	 * @return
    	 */
    	@RequestMapping("/createSession")
    	public String createSession(HttpServletRequest request, String nameValue) {
    		/**
    		 * 看一下这段代码
    		 * 表示什么意思呢
    		 * getSession()他这里面可以传true或者false
    		 * 不知道你们有没有印象
    		 * 你们现在可能不理解true和false什么意思
    		 * 不理解没关系
    		 * 待会讲集群的时候你们瞬间就理解了
    		 * 默认是true
    		 * 这段代码表示什么意思呢
    		 * 默认 创建一个session
    		 * 创建一个SESSION的时候
    		 * 默认值是true
    		 * 一旦是为true的情况下的时候
    		 * 没有找到对应的SESSION的时候
    		 * 自动创建SESSION
    		 * 他如果去自动创建这样的一个SESSION的时候
    		 * 一个SESSION他和什么相似
    		 * session分为sessionId和sessionValue
    		 * 这个你们知道吧
    		 * 这个我相信你们知道
    		 * 那么在这里我问大家一个问题
    		 * session他和什么比较相似
    		 * 我不说map集合
    		 * session和我们之前学的什么知识比较相似
    		 * 和TOKEN
    		 * 不是cookie
    		 * 他和token非常相似
    		 * session本身来说是不是临时的
    		 * 是不是一个临时的
    		 * 他如果是临时的话
    		 * 不是永久有效的
    		 * 既然是临时的话
    		 * 和token是不是很相似
    		 * 因为我令牌也是做临时的
    		 * sessionId和token令牌也是非常相似的
    		 * 保证临时且唯一
    		 * 这个你们一定要记住
    		 * 我在后面会讲到
    		 * 很多公司分布式SESSION用什么解决呢
    		 * 就用token解决
    		 * 没有用到Spring-Session
    		 * 客户端向服务器端肯定会发起一个createSession请求
    		 * 如果在发起createSession请求的时候
    		 * 注意看代码
    		 * 服务器端接收到客户端请求之后
    		 * 会创建一个session
    		 * 创建完一个session之后
    		 * 通过响应头返回一个sessionId
    		 * 这个是请求的过程
    		 * 这个叫做请求过程
    		 * 那么反过来再看
    		 * 叫做响应的过程
    		 * 注意看一下
    		 * 请求和响应过程
    		 * 第二次请求的时候是这样的过程
    		 * 这个时候什么意思呢
    		 * 客户端向服务器端发起请求的时候
    		 * 它会返回一个sessionId
    		 * 返回一个sessionId给客户端
    		 * 是不是浏览器
    		 * 浏览器它会怎么做呢
    		 * 浏览器获取到sessionId以后
    		 * 保存在本地
    		 * 既然他的sessionId是保存在本地的话
    		 * 那么他和什么技术比较相似
    		 * 想想他和什么技术比较相似
    		 * 是不是叫做cookie
    		 * 是不是非常非常相似
    		 * 那么浏览器这个时候要怎么做呢
    		 * 那么在这边我要讲的是什么呢
    		 * 第二次请求
    		 * 客户端读取到本地的sessionId
    		 * 存放在请求头中
    		 * 服务器端从请求头中获取到对应的sessionId
    		 * 使用sessionId在本地内存中查询
    		 * 你们现在可能还不明白什么意思
    		 * 在这里我们打开我们的开发者工具
    		 * 当我们发起一个createSession请求的时候
    		 * 看一下它是一个什么过程
    		 * 我们把日志打开
    		 * 一旦向createSession
    		 * 首先默认是为true的
    		 * 他如果没有sessionId的话
    		 * 创建一个session
    		 * 创建一个SESSION之后
    		 * 返回一个sessionId
    		 * 对应的是存放的值
    		 * 我故意把这个session打印出来了
    		 * 对应的值是存放在对应的sessionId里面的
    		 * 那你们注意看一个效果
    		 * 我在这个地方去查询的时候
    		 * 我们再次发起请求
    		 * 找到netWork
    		 * 找到响应头
    		 * 响应头是不是把sessionId返回给客户端
    		 * 也就是一个SESSIONID
    		 * 客户端拿到sessionId保存在本地了
    		 * 
    		 * 
    		 */
    		HttpSession session = request.getSession();
    		System.out.println(
    				"存入Session  sessionid:信息" + session.getId() + ",nameValue:" + nameValue + ",serverPort:" + serverPort);
    		/**
    		 * 在这里存放一个nameValue这个值
    		 * 
    		 */
    		session.setAttribute("name", nameValue);
    		return "success-" + serverPort;
    	}
    
    	// 获取session 会话
    	/**
    	 * 这里有一个获取SESSION
    	 * 
    	 * 
    	 * @param request
    	 * @return
    	 */
    	@RequestMapping("/getSession")
    	public Object getSession(HttpServletRequest request) {
    		// 设置为true 情况下的时候,客户端使用对应的sessionid 查询不到对应的sesison 会直接创建一个新的session
    		// 设置为false 情况下的时候,客户端使用对应的sessionid 查询不到对应的sesison 不 会直接创建一个新的session
    		/**
    		 * 这里表示获取SESSION
    		 * 
    		 * 
    		 */
    		HttpSession session = request.getSession(false);
    		if (session == null) {
    			return serverPort + "  该服务器上没有存放对应的session值";
    		}
    		System.out.println("获取Session sessionid:信息" + session.getId() + "serverPort:" + serverPort);
    		/**
    		 * 这里直接获取getName
    		 * 
    		 * 
    		 */
    		Object value = session.getAttribute("name");
    		return serverPort + "-" + value;
    	}
    
    }
    
    package com.learn;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    /**
     * 
     * @author Leon.Sun
     *
     */
    @SpringBootApplication
    public class AppSession {
    
    	public static void main(String[] args) {
    		/**
    		 * 我们直接启动这个项目
    		 * 
    		 */
    		SpringApplication.run(AppSession.class, args);
    	}
    
    }
    

     

    展开全文
  • 本篇介绍Spring-Session的整个实现的原理。以及对核心的源码进行简单的介绍! 实现原理介绍 实现原理这里简单说明描述: 就是当Web服务器接收到http请求后,当请求进入对应的Filter进行过滤,将原本...

    做一个积极的人

    编码、改bug、提升自己

    我有一个乐园,面向编程,春暖花开!

    =================================================

    对人工智能感兴趣的伙伴,分享一个我朋友的人工智能教程。零基础!通俗易懂!风趣幽默!大家可以看看是否对自己有帮助,点击这里查看教程

    =================================================

    知其然,还要知其所以然 !

    本篇介绍Spring-Session的整个实现的原理。以及对核心的源码进行简单的介绍!

    实现原理介绍

    实现原理这里简单说明描述:

    就是当Web服务器接收到http请求后,当请求进入对应的Filter进行过滤,将原本需要由web服务器创建会话的过程转交给Spring-Session进行创建,本来创建的会话保存在Web服务器内存中,通过Spring-Session创建的会话信息可以保存第三方的服务中,如:redis,mysql等。Web服务器之间通过连接第三方服务来共享数据,实现Session共享!

    实现原理结构草图

    整个实现流程和源码详细介绍

    本次源码介绍基于上一篇内容,并且在保存Session的时候只会分析使用JedisConnectionFactory实现的RedisConnectionFactory !

    1.SessionRepositoryFilter和JedisConnectionFactory注册过程

    流程:

    SessionRepositoryFilter和JedisConnectionFactory注册过程

    说明:

    1.、启动WEB项目的时候,会读取web.xml,读取顺序content-param --> listener --> filter --> servlet
    
    2.、ContextLoaderListener监听器的作用就是启动Web容器时,自动装配ApplicationContext的配置信息
    
    3、初始化根web应用程序上下文。
    
    4、SpringHttpSessionConfiguration注册 springSessionRepositoryFilter :bean,RedisHttpSessionConfiguration 注册 sessionRedisTemplate : bean  和 sessionRepository : bean
    
    5、配置文件配置JedisConnectionFactory implements RedisConnectionFactory ,创建 jedisConnectionFactory bean
    
    

    代码分析如下:

    1. web.xml ,加载了xml配置文件,并初始化web应用上下文
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath*:spring/*xml</param-value>
    </context-param>
    
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
      
    

    2.application-session.xml中,配置 RedisHttpSessionConfiguration的bean和JedisConnectionFactory的bean,web应用初始化加载bean!

    <!--创建一个Spring Bean的名称springSessionRepositoryFilter实现过滤器。
        筛选器负责将HttpSession实现替换为Spring会话支持。在这个实例中,Spring会话得到了Redis的支持。-->
        <bean class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration"/>
    
        <!--创建了一个RedisConnectionFactory,它将Spring会话连接到Redis服务器。我们配置连接到默认端口(6379)上的本地主机!-->
        <!--集群Redis-->
        <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
            <!--Redis-CLuster-->
            <constructor-arg index="0" ref="redisClusterConfig"/>
    
            <!--配置Redis连接池 ,可以不配置,使用默认就行!-->
            <constructor-arg index="1" ref="jedisPoolConfig"/>
        </bean>
        
    
    1. ContextLoaderListener
    /**
    * 初始化根web应用程序上下文。
    */
    @Override
    public void contextInitialized(ServletContextEvent event) {
    initWebApplicationContext(event.getServletContext());
    }
    	
    

    4.RedisHttpSessionConfiguration类图

    RedisHttpSessionConfiguration类图

    RedisHttpSessionConfiguration注释
    RedisHttpSessionConfiguration继承了SpringHttpSessionConfiguration

    public class RedisHttpSessionConfiguration extends SpringHttpSessionConfiguration
    		implements EmbeddedValueResolverAware, ImportAware {
    		
    

    4.1 SpringHttpSessionConfiguration 创建一个名称为springSessionRepositoryFilter的bean

    @Bean
    public <S extends ExpiringSession> SessionRepositoryFilter<? extends ExpiringSession> springSessionRepositoryFilter(
        SessionRepository<S> sessionRepository) {
        SessionRepositoryFilter<S> sessionRepositoryFilter = new SessionRepositoryFilter<S>(
            sessionRepository);
        sessionRepositoryFilter.setServletContext(this.servletContext);
        if (this.httpSessionStrategy instanceof MultiHttpSessionStrategy) {
            sessionRepositoryFilter.setHttpSessionStrategy(
                (MultiHttpSessionStrategy) this.httpSessionStrategy);
        }
        else {
            sessionRepositoryFilter.setHttpSessionStrategy(this.httpSessionStrategy);
        }
        return sessionRepositoryFilter;
    }
    
    
    

    4.2 创建RedisHttpSessionConfiguration#RedisTemplate bean的名称为sessionRedisTemplate

    @Bean
    public RedisTemplate<Object, Object> sessionRedisTemplate(
        RedisConnectionFactory connectionFactory) {
        //实例化 RedisTemplate 
        RedisTemplate<Object, Object> template = new RedisTemplate<Object, Object>();
        //设置key序列化 StringRedisSerializer
        template.setKeySerializer(new StringRedisSerializer());
        //设置Hash key  StringRedisSerializer
        template.setHashKeySerializer(new StringRedisSerializer());
        if (this.defaultRedisSerializer != null) {
            template.setDefaultSerializer(this.defaultRedisSerializer);
        }
        //设置 connectionFactory。第五步创建的(实际connectionFactory加载过程和讲解过程顺序不一样)
        template.setConnectionFactory(connectionFactory);
        return template;
    }
    
    

    4.3 创建RedisHttpSessionConfiguration#RedisOperationsSessionRepository bean的名称为sessionRepository

    @Bean
    public RedisOperationsSessionRepository sessionRepository(
        //使用sessionRedisTemplate bean
        @Qualifier("sessionRedisTemplate") RedisOperations<Object, Object> sessionRedisTemplate,
        ApplicationEventPublisher applicationEventPublisher) {
    
        //實例化RedisOperationsSessionRepository
        RedisOperationsSessionRepository sessionRepository = new RedisOperationsSessionRepository(
            sessionRedisTemplate);
        //設置applicationEventPublisher
        sessionRepository.setApplicationEventPublisher(applicationEventPublisher);
        //設置最大的失效時間 maxInactiveIntervalInSeconds = 1800
        sessionRepository
            .setDefaultMaxInactiveInterval(this.maxInactiveIntervalInSeconds);
        if (this.defaultRedisSerializer != null) {
            sessionRepository.setDefaultSerializer(this.defaultRedisSerializer);
        }
    
        String redisNamespace = getRedisNamespace();
        if (StringUtils.hasText(redisNamespace)) {
            sessionRepository.setRedisKeyNamespace(redisNamespace);
        }
    
        sessionRepository.setRedisFlushMode(this.redisFlushMode);
        return sessionRepository;
    }
    
    
    1. 创建 RedisConnectionFactory bean为 jedisConnectionFactory

    JedisConnectionFactory类图

    <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
    
    

    2.SessionRepositoryFilter添加到FilterChain

    流程:

    SessionRepositoryFilter添加到FIlterChain

    说明:

    1 和 2、在Servlet3.0规范中,Servlet容器启动时会自动扫描javax.servlet.ServletContainerInitializer的实现类,在实现类中我们可以定制需要加载的类。 通过注解@HandlesTypes(WebApplicationInitializer.class),让Servlet容器在启动该类时,会自动寻找所有的WebApplicationInitializer实现类。
    
    2.1、insertSessionRepositoryFilter 方法通过filterName获取 SessionRepositoryFilter ,并创建了 new DelegatingFilterProxy(filterName);
    
    3 和 4、然后将filter添加到FilterChain中
    
    
    

    1.ServletContainerInitializer的实现类加载和通过注解@HandlesTypes(WebApplicationInitializer.class)实现类的加载

    //加载实现类
    @HandlesTypes(WebApplicationInitializer.class)
    //SpringServletContainerInitializer实现ServletContainerInitializer
    public class SpringServletContainerInitializer implements ServletContainerInitializer {
    
    //------------
    
    

    2.AbstractHttpSessionApplicationInitializer实现WebApplicationInitializer进行加载

    @Order(100)
    public abstract class AbstractHttpSessionApplicationInitializer
        implements WebApplicationInitializer {
    
    

    2.1 onStartup

    public void onStartup(ServletContext servletContext) throws ServletException {
        beforeSessionRepositoryFilter(servletContext);
        if (this.configurationClasses != null) {
            AnnotationConfigWebApplicationContext rootAppContext = new AnnotationConfigWebApplicationContext();
            rootAppContext.register(this.configurationClasses);
            servletContext.addListener(new ContextLoaderListener(rootAppContext));
        }
        //添加Filter
        insertSessionRepositoryFilter(servletContext);
        afterSessionRepositoryFilter(servletContext);
    }
    
    

    2.1.1.insertSessionRepositoryFilter

    /**
    	 * 注册springSessionRepositoryFilter
    	 * @param servletContext the {@link ServletContext}
    	 */
    private void insertSessionRepositoryFilter(ServletContext servletContext) {
        // DEFAULT_FILTER_NAME = "springSessionRepositoryFilter"
        String filterName = DEFAULT_FILTER_NAME;
        //通过filterName创建 DelegatingFilterProxy
        DelegatingFilterProxy springSessionRepositoryFilter = new DelegatingFilterProxy(
            filterName);
        String contextAttribute = getWebApplicationContextAttribute();
        if (contextAttribute != null) {
            springSessionRepositoryFilter.setContextAttribute(contextAttribute);
        }
        //根据filterName和上下文添加Filter到FilterChain
        registerFilter(servletContext, true, filterName, springSessionRepositoryFilter);
    }
    
    
    1. registerFilter
    private void registerFilter(ServletContext servletContext,
                                boolean insertBeforeOtherFilters, String filterName, Filter filter) {
        Dynamic registration = servletContext.addFilter(filterName, filter);
        if (registration == null) {
            throw new IllegalStateException(
                "Duplicate Filter registration for '" + filterName
                + "'. Check to ensure the Filter is only configured once.");
        }
        //是否支持异步,默认 true
        registration.setAsyncSupported(isAsyncSessionSupported());
        //得到DispatcherType springSessionRepositoryFilter
        EnumSet<DispatcherType> dispatcherTypes = getSessionDispatcherTypes();
        //添加一个带有给定url模式的筛选器映射和由这个FilterRegistration表示的过滤器的分派器类型。 过滤器映射按照添加它们的顺序进行匹配。
        registration.addMappingForUrlPatterns(dispatcherTypes, !insertBeforeOtherFilters,
                                              "/*");
    }
    
    1. addFilter将Filter添加到ServletContext中
    public FilterRegistration.Dynamic addFilter(
        String filterName, Filter filter);
    
    

    3.SessionRepositoryFilter拦截过程

    流程:

    SessionRepositoryFilter拦截过程

    说明:

    1、请求被DelegatingFilterProxy : 拦截到,然后执行doFilter方法,在doFilter中找到执行的代理类。
    2、OncePerRequestFilter : 代理Filter执行doFilter方法,然后调用抽象方法doFilterInternal
    3、SessionRepositoryFilter 继承了OncePerRequestFilter,实现了doFilterInternal,这个方法一个封装一个wrappedRequest,通过执行commitSession保存session信息到redis
    
    

    1请求进来,被DelegatingFilterProxy 拦截到,在web.xml中进行了配置
    1.1 执行doFilter

    如果没有指定目标bean名称,请使用筛选器名称。
    @Override
    	public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
        throws ServletException, IOException {
    
        // 如果需要,延迟初始化委托。 necessary.
        Filter delegateToUse = this.delegate;
        if (delegateToUse == null) {
            synchronized (this.delegateMonitor) {
                if (this.delegate == null) {
                    WebApplicationContext wac = findWebApplicationContext();
                    if (wac == null) {
                        throw new IllegalStateException("No WebApplicationContext found: " +
                                                        "no ContextLoaderListener or DispatcherServlet registered?");
                    }
                    this.delegate = initDelegate(wac);
                }
                delegateToUse = this.delegate;
            }
        }
    
        // 让委托执行实际的doFilter操作
        invokeDelegate(delegateToUse, request, response, filterChain);
    }
    

    1.2 initDelegate

    protected Filter initDelegate(WebApplicationContext wac) throws ServletException {
        //可以获取到SessionRepositoryFilter [备注1]
        Filter delegate = wac.getBean(getTargetBeanName(), Filter.class);
        if (isTargetFilterLifecycle()) {
            delegate.init(getFilterConfig());
        }
        return delegate;
    }
    
    //[备注1] 因为 :SessionRepositoryFilter是一个优先级最高的javax.servlet.Filter
    /*
    @Order(SessionRepositoryFilter.DEFAULT_ORDER)
    public class SessionRepositoryFilter<S extends ExpiringSession>
    		extends OncePerRequestFilter {
    
    */
    
    1. delegate.doFilter();
    protected void invokeDelegate(
        Filter delegate, ServletRequest request, ServletResponse response, FilterChain filterChain)
        throws ServletException, IOException {
        //代理去执行doFilter,代理为SessionRepositoryFilter
        delegate.doFilter(request, response, filterChain);
    }
    
    

    2.1 OncePerRequestFilter#doFilter

    public final void doFilter(ServletRequest request, ServletResponse response,
                               FilterChain filterChain) throws ServletException, IOException {
    
        if (!(request instanceof HttpServletRequest)
            || !(response instanceof HttpServletResponse)) {
            throw new ServletException(
                "OncePerRequestFilter just supports HTTP requests");
        }
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        boolean hasAlreadyFilteredAttribute = request
            .getAttribute(this.alreadyFilteredAttributeName) != null;
    
        if (hasAlreadyFilteredAttribute) {
    
            //在不调用此过滤器的情况下进行…
            filterChain.doFilter(request, response);
        }
        else {
            // 调用这个过滤器…
            request.setAttribute(this.alreadyFilteredAttributeName, Boolean.TRUE);
            try {
                //doFilterInternal是个抽象方法
                doFilterInternal(httpRequest, httpResponse, filterChain);
            }
            finally {
                // 删除此请求的“已过滤”请求属性。
                request.removeAttribute(this.alreadyFilteredAttributeName);
            }
        }
    }
    
    
    1. 执行SessionRepositoryFilter#doFilterInternal
    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response, FilterChain filterChain)
        throws ServletException, IOException {
        request.setAttribute(SESSION_REPOSITORY_ATTR, this.sessionRepository);
        //使用HttpServletRequest 、HttpServletResponse和servletContext创建一个SessionRepositoryRequestWrapper
    
        SessionRepositoryRequestWrapper wrappedRequest = new SessionRepositoryRequestWrapper(
            request, response, this.servletContext);
        SessionRepositoryResponseWrapper wrappedResponse = new SessionRepositoryResponseWrapper(
            wrappedRequest, response);
    
        //使用CookieHttpSessionStrategy重新包装了 HttpServletRequest
        HttpServletRequest strategyRequest = this.httpSessionStrategy
            .wrapRequest(wrappedRequest, wrappedResponse);
        HttpServletResponse strategyResponse = this.httpSessionStrategy
            .wrapResponse(wrappedRequest, wrappedResponse);
    
        try {
            //执行其他过滤器
            filterChain.doFilter(strategyRequest, strategyResponse);
        }
        finally {
            //保存session信息
            wrappedRequest.commitSession();
        }
    }
    
    

    4 .wrappedRequest.commitSession() 看下第四大点分析

    4.SessionRepository保存session数据

    流程:
    SessionRepository保存session数据

    说明:

    1、提交session保存
    2、获取当前session,这一步比较重要,获取了一个HttpSessionWrapper,这个HttpSessionWrapper替换了HTTPSession
    3、wrappedSession获取当前的Session
    4、使用 RedisTemplate 保存Session内容,并通过调用RedisConnection 使用它的实现类JedisClusterConnection获取redis连接
    
    

    1.commitSession

    /**
    *使用HttpSessionStrategy将会话id写入响应。 *保存会话。
    */
    private void commitSession() {
        HttpSessionWrapper wrappedSession = getCurrentSession();
        if (wrappedSession == null) {
            if (isInvalidateClientSession()) {
                SessionRepositoryFilter.this.httpSessionStrategy
                    .onInvalidateSession(this, this.response);
            }
        }
        else {
            S session = wrappedSession.getSession();
            SessionRepositoryFilter.this.sessionRepository.save(session);
            if (!isRequestedSessionIdValid()
                || !session.getId().equals(getRequestedSessionId())) {
                SessionRepositoryFilter.this.httpSessionStrategy.onNewSession(session,
                                                                              this, this.response);
            }
        }
    }
    

    2.getCurrentSession

    会话存储库请求属性名。
    public static final String SESSION_REPOSITORY_ATTR = SessionRepository.class
        .getName();
    
    private static final String CURRENT_SESSION_ATTR = SESSION_REPOSITORY_ATTR
    			+ ".CURRENT_SESSION";
    
    private HttpSessionWrapper getCurrentSession() {
        return (HttpSessionWrapper)
            //获取session
            getAttribute(CURRENT_SESSION_ATTR);
    }
    
    /**
         * 此方法的默认行为是在包装请求对象上调用getAttribute(字符串名称)。
         */
    public Object getAttribute(String name) {
        //这里的request就是上面封装的
        return this.request.getAttribute(name);
    }
    

    3 .wrappedSession.getSession

    //返回 RedisSession
    S session = wrappedSession.getSession();
    //-------------------------
    public S getSession() {
        return this.session;
    }
    class ExpiringSessionHttpSession<S extends ExpiringSession> implements HttpSession {
        private S session;
    
    
     final class RedisSession implements ExpiringSession {
    
    

    4.save,实际是调用 RedisOperationsSessionRepository的 RedisOperations 操作

    SessionRepositoryFilter.this.sessionRepository.save(session);
    
    //this.sessionRepository =  SessionRepository<S> sessionRepository;
    
    //--------------------------------
    //这个RedisOperationsSessionRepository是之前就创建好的
    public class RedisOperationsSessionRepository implements
        FindByIndexNameSessionRepository<RedisOperationsSessionRepository.RedisSession>,
    MessageListener {
    
    
        public interface FindByIndexNameSessionRepository<S extends Session>
            extends SessionRepository<S> {
    
            //---------------------------
    
    
            public void save(RedisSession session) {
                //4.1saveDelta
                session.saveDelta();
                if (session.isNew()) {
                    //4.2调用
                    String sessionCreatedKey = getSessionCreatedChannel(session.getId());
                    //4.3convertAndSend
                    //RedisOperations = this.sessionRedisOperations
                    this.sessionRedisOperations.convertAndSend(sessionCreatedKey, session.delta);
                    session.setNew(false);
                }
            }
    	
    	
    

    其中RedisOperationsSessionRepository 里面介绍保存的详细过程,具体请看文档说明:

    Class RedisOperationsSessionRepository

    因为 RedisTemplate implements RedisOperations,实际进行操作的是RedisTemplate,RedisTemplate通过RedisConnection进行数据add和remove等

    public class RedisTemplate<K, V>
    extends RedisAccessor
    implements RedisOperations<K, V>, BeanClassLoaderAware
    

    总结

    本系列到这里也就结束了,本次话的整个流程图,会上传到github上,使用Jude打开就可以看!

    如果有什么地方写的不对或者有想和我一起探讨一下的,欢迎加我的QQ或者QQ群!

    记录一个小点:

    Spring Session + Redis实现分布式Session共享 有个非常大的缺陷, 无法实现跨域名共享session , 只能在单台服务器上共享session , 因为是依赖cookie做的 , cookie 无法跨域 pring Session一般是用于多台服务器负载均衡时共享Session的,都是同一个域名,不会跨域。你想要的跨域的登录,可能需要SSO单点登录。

    参考博文

    【Spring】Spring Session的简单搭建与源码阅读

    利用spring session解决共享Session问题

    Spring Session解决分布式Session问题的实现原理

    spring-session简介、使用及实现原理


    本系列教程

    【入门】分布式Session一致性入门简介

    【第一篇】Spring-Session实现Session共享入门教程

    【第二篇】Spring-Session实现Session共享Redis集群方式配置教程

    【第三篇】Spring-Session实现Session共享实现原理以及源码解析

    本系列的源码下载地址:learn-spring-session-core


    谢谢你的阅读,如果您觉得这篇博文对你有帮助,请点赞或者喜欢,让更多的人看到!祝你每天开心愉快!



    不管做什么,只要坚持下去就会看到不一样!在路上,不卑不亢!

    愿你我在人生的路上能都变成最好的自己,能够成为一个独挡一面的人

    © 每天都在变得更好的阿飞云

    展开全文
  • 而当我们在这个网站浏览一段时间后,它会产生我们浏览的记录,而且有...这些简单实用的功能就是通过Cookie与Session实现的,接下来,让我们一起探讨一下它们是如何运行的。 1、概念 Cookie 有时也用其复数形式Co
  • session实现原理

    千次阅读 2017-08-09 18:09:26
    一、Session简单介绍  在WEB开发中,服务器可以为每个用户浏览器创建一个会话对象(session对象),注意:一个浏览器独占一个session对象(默认情况下)。因此,在需要保存用户数据时,服务器程序可以把用户数据写...
  • Session实现原理

    万次阅读 2008-09-28 15:07:00
    Session实现原理2008-08-26 17:11关键字: jsp,sessionHTTP协议 ( http://www.w3.org/Protocols/ )是“一次性单向”协议。 服务端不能主动连接客户端,只能被动等待并答复客户端请求。客户端连接服务端,发出一个...
  • Session实现用户登录

    2018-11-02 14:18:17
    前端界面&lt;!DOCTYPE html&gt; &lt;html&gt; &lt;head&gt; &lt;meta charset="UTF-8"&gt; &lt;title&gt;Insert title here&...form action=&
  • session原理及实现共享

    万次阅读 2017-04-01 19:22:08
    http协议是无状态的,即你连续访问某个网页100次和访问1次对服务器来说是没有区别对待的,因为它记不住你。 那么,在一些场合,确实需要服务器记住当前用户怎么办?比如用户登录邮箱后,接下来要收... ...原理很简
  • Tomcat Session总结及底层实现

    千次阅读 2019-05-13 13:08:52
    @Author 风一样的码农 @HomePageUrl http://www.cnblogs.com/chenpi/ ... 阅读目录 什么是Session Session的目的 ...Tomcat中的session实现 第一次访问时新建session(此部分为原创) session存在的问题 ...
  • session实现与工作原理浏览器和服务器采用http无状态的通讯,为了保持客户端的状态,使用session来达到这个目的。然而服务端是怎么样标示不同的客户端或用户呢?这里我们可以使用生活中的一个例子,假如你参加一个...
  • 分布式session的几种实现方式

    千次阅读 2018-05-31 16:13:43
    在搭建完集群环境后,不得不考虑的一个问题就是用户访问产生的session如何处理。如果不做任何处理的话,用户将出现频繁登录的现象,比如集群中存在A、B两台服务器,用户在第一次访问网站时,Nginx通过其负载均衡机制...
  • 当登录验证通过后,在欢迎页面点击退出按钮后,返回到登录界面,此时如果通过后退回到 欢迎页面或者直接访问欢迎页面,怎样保证能跳转到登陆页面。。。
  • Cookie和Session实现保存登录状态免登录

    万次阅读 多人点赞 2018-09-11 21:56:13
    首先Cookie和Session都是为了状态管理,HTTP协议是无状态的,不能保存每次提交... 对于那些需要多次提交数据才能完成的Web操作,比如登录来说,就成问题了。所以需要状态管理也就是通过Cookie和Session。 一.Cook...
  • Session实现用户登录(九)

    万次阅读 多人点赞 2017-11-16 19:41:51
    (一)创建登录页面<!DOCTYPE html> <title>Insert title here <form action="/Project01/LoginServlet" method="post"> 用户名:<input name="username" type="t
  • java Cookie+Session实现自动登录

    千次阅读 2016-01-03 18:04:36
    java结合Cookie,Session实现网站的自动登录
  • 利用session实现登录页面

    千次阅读 2019-10-14 11:22:55
  • 使用session实现登录判断功能

    万次阅读 2017-04-15 20:17:32
    登录界面: 2个页面,一个index.aspx登录界面,一个view.aspx登录后的显示界面 如果一开始直接登录view.aspx,会显示没有登录,然后提示用户进入登录界面登录(index.aspx) 进入index.aspx界面注册: ...
  • session为每个浏览器独创一个区域,有一个key,通过key可以找到独享的区域 下面这个代码利用的就是session,每个购物车是一个mao集合,然后把这个map集合放到session中作为每个浏览器独享的区域 如果下面代码哪里...
  • 本篇开始学习Spring-Session相关的一些知识学习整理,让我们开始吧! Spring-Session介绍 Spring-Session使用的场景? HttpSession是通过Servlet容器进行创建和管理的,在单机环境中。通过Http请求创建的...
  • 利用session实现用户登录

    千次阅读 2017-04-21 19:50:11
    public class LoginServlet extends HttpServlet {  public void doGet(HttpServletRequest request, HttpServletResponse response)  throws ServletException, IOException {  requ
  • spring session 实现单点登录

    千次阅读 2018-01-30 12:44:42
    介绍了Spring session 的使用,包括从jar 包的导入,redis 数据库的配置,spring session配置文件的编写,到最后单点登录功能的实现实现过程 在Web项目开发中,会话管理是一个很重要的部分,用于存储与用户...
  • session实现购物车

    千次阅读 2018-03-09 17:59:23
    功能:应用会话技术实现购物车功能,点击货物,将货物保存至购物车,实现购物车的增添清空功能主界面代码:&lt;%@ page contentType="text/html;charset=UTF-8" language="java" ...
  • 使用session实现添加购物车功能

    千次阅读 2018-07-15 08:43:41
    session: 服务器端会话技术. 当我们第一次访问的服务器的时候,服务器获取id, 能获取id 要拿着这个id去服务器中查找有无此session 若查找到了:直接拿过来时候,将数据保存,需要将当前sessin的id返回给浏览器 若...
  • SpringMVC使用session实现简单登录

    万次阅读 2016-08-02 15:40:13
    1.首先为了能直观地在jsp页面体现session的内容,我使用了jstl表达式,首先在pom.xml中引入jstl的依赖 jstl jstl 1.2 2.编写登录界面以及登录成功界面 登录界面 ; charset=utf-8" pageEncoding=...
  • Beego利用Session实现简单的登录验证

    千次阅读 2019-10-09 13:39:19
    首先需要在框架中开启Session模块,可以通过写入app.conf配置,也可以通过入口函数(main.go)配置,我这里选择后者: package main import ( "github.com/astaxie/beego" _ "testbeego/routers" ) func ...
  • 业务中可以利用简单的map集合来实现购物车通过分析我们知道,如果想获取用户的购物车,且是自己的购物车,里面寄存了我们曾购买的物品属性和数量,我们想到了session这个对象,先来了解下session,以下资料借鉴网络 ...
  • 我这边对应redis的使用介绍分开五篇,此为篇章五。 (建议初学者五篇都看看,那对于redis的基本使用操作及一些消息的订阅分布都是没问题的了) 首先,导包。...在pom.xml文件里面加入以下: ...
  • 使用session实现网站N天免登陆

    千次阅读 2015-08-19 20:30:57
     方式一:首先想到的是使用cookie保存用户登录信息,设置有效期,在用户下次访问时免去登录环节,直接通过cookie获取用户信息。  方式二:直接将session会话保存,用户下次访问时,继续使用这个session。 相比...
  • 利用httpSessionListener监听sessionCreated 和sessionDestoryed方法 sessionCreated{ application(或servletContext)对象构建一个变量num,因为直到web应用关闭,num才失效,所以可以用来统计在线人数。...

空空如也

1 2 3 4 5 ... 20
收藏数 667,642
精华内容 267,056
关键字:

session实现