用axios怎样解决共享session的问题
方法/步骤
1
客户端SessionID值唯一;
对于不同的域名:主域名、子域名、跨站点域名或跨服务器域名,用户在打开页面时会产生不同的SessionID
为了使这些站点在用户登录时只登录一次,那我们就要解决SessionID的问题,必须使SessionID在这些共享Session的站点中只产生一次。而SessionID是存储在客户端的cookie之中键值为ASPNET_SessionId的一个字符串(也可以存储在URL中,这里不作使介绍),为此只须使各站点存储的SPNET_SessionId唯一即可。
2
因每个客户端在打开时会产生一个SessionID,为此我们要做的就是重置SessionID。我们可以在继承HttpModule,在结束请求时重写SessionID。
为使用以上代码,须配置下面节点项。
<httpModules>
<add name="节点名称" type="类名全称, 程序集"/>
</httpModules>
3
Session值的共享;
配置sessionState置节点,使用StateServer或SQLServer来实现Session共享。
为实现跨服务器共享,必须在Webconfig配置:
<machineKey decryptionKey="FD69B2EB9A11E3063518F1932E314E4AA1577BF0B824F369" validationKey="5F32295C31223A362286DD5777916FCD0FD2A8EF882783FD3E29AB1FCDFE931F8FA45A8E468B7A40269E50A748778CBB8DB2262D44A86BBCEA96DCA46CBC05C3" validation="SHA1" decryption="Auto"/>
并且,不同服务器上站点配置必须用相同的Webconfig,各站点目录配置也要相同。
4
使用StateServer:
存储Session的服务器必须开启StateServer:ASPNET状态服务。只有机器重起的情况下才导致Session丢失。
<sessionState cookieless="false" timeout="50" mode="StateServer" stateConnectionString="tcpip=IpAddress:42424"/>
若StateServer在本机存储,则IpAddress为:127001;若StateServer为远程服务器,则为IpAddress为远程服务器IP地址,并且修改注册表项如下:
Windows Registry Editor Version 500
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\aspnet_state\Parameters]
"Port"=dword:0000a5b8
"AllowRemoteConnection"=dword:00000001
5
使用SQLServer:
必须开启SQLServer代理服务,此服务负责清除过期的Session,若没有开服务,则Session不会过期。
使用SQLServer在机器重启后Session不会丢失。
Webconfig配置:
<sessionState mode="SQLServer" sqlConnectionString="server=DBIpAddress; uid=myid; pwd=mypwd;"/>
6
数据库配置:
使用aspnet_regsqlexe工具
ASPNET 20版本后微软提供了aspnet_regsqlexe工具可以方便的配置Session数据库该工具位于 Web 服务器上的"系统根目录\MicrosoftNET\Framework\版本号"文件夹中
使用举例:
aspnet_regsqlexe -S -U sa -P 123456 -ssadd -sstype p
-S参数:
表示数据库实例名称 可以用""表示本机
-U和-P参数:
表示用户名和密码
-E参数:
可以再-U –P 与 -E中选择一组 –E表示以当前系统用户通过windows身份验证登录数据库, -U -P则是使用SqlServer用户登录数据库
-ssadd / –ssremove 参数:
-ssadd表示是添加Session数据库, -ssremove表示移除Session数据库
sstype 参数说明:
t
将会话数据存储到 SQL Server tempdb 数据库中。这是默认设置。如果将会话数据存储到 tempdb 数据库中,则在重新启动 SQL Server 时将丢失会话数据。
p
将会话数据存储到 ASPState 数据库中,而不是存储到 tempdb 数据库中。
c
将会话数据存储到自定义数据库中。如果指定 c 选项,则还必须使用 -d 选项包括自定义数据库的名称。
sessionState参数说明:
说明
allowCustomSqlDatabase
可选的 Boolean 属性。
指定会话状态 SQL 数据库是否可以是自定义数据库(而不是 ASPNET 默认数据库)。如果为 false,则不能指定初始目录或数据库作为 sqlConnectionString 属性的值。默认会话状态 SQL 数据库为 ASPState 数据库。有关更多信息,请参见会话状态模式。
此属性是 NET Framework 20 版中的新属性。
默认值为 false。
cookieless
可选的 HttpCookieMode 属性。
指定对于 Web 应用程序使用 Cookie 的方式。
cookieless 属性可以为下列可能值之一。默认值为 UseCookies。
值
说明
AutoDetect
ASPNET 确定请求浏览器或请求设备是否支持 Cookie。如果请求浏览器或请求设备支持 Cookie,则 AutoDetect 使用 Cookie 来保留用户数据;否则,将在查询字符串中使用一个标识符。如果浏览器或设备支持 Cookie,但当前禁用了 Cookie,则请求功能仍会使用 Cookie。
UseCookies
无论浏览器或设备是否支持 Cookie,都使用 Cookie 来保留用户数据。
UseDeviceProfile
ASPNET 根据 HttpBrowserCapabilities 设置来确定是否使用 Cookie。如果 HttpBrowserCapabilities 设置指示浏览器或设备支持 Cookie,将使用 Cookie;否则,将在查询字符串中使用一个标识符。
UseUri
无论浏览器或设备是否支持 Cookie,调用功能都使用查询字符串来存储标识符。
cookieName
可选的 String 属性。
指定存储会话标识符的 Cookie 的名称。
此属性是 NET Framework 20 版中的新属性。
默认值为 "ASPNET_SessionId"。
customProvider
可选的 String 属性。
指定用于存储和检索会话状态数据的自定义会话状态提供程序的名称。该提供程序在 providers 元素中指定。仅当会话状态模式设置为 Custom 值时,才使用该提供程序。有关更多信息,请参见会话状态模式。
此属性是 NET Framework 20 版中的新属性。
默认值为空字符串 ("")。
mode
可选的 SessionStateMode 属性。
指定存储会话状态值的位置。有关更多信息,请参见会话状态模式。
mode 属性可以为下列可能值之一。默认值为 InProc。
值
说明
Custom
会话状态将使用自定义数据存储区来存储会话状态信息。
InProc
会话处于正在处理 ASPNET 辅助进程的状态。
Off
会话状态被禁用。
SQLServer
会话状态将使用进程外 SQL Server 数据库来存储状态信息。
StateServer
会话状态将使用进程外 ASPNET 状态服务来存储状态信息。
partitionResolverType
可选的 String 属性。
指定在哪里存储会话状态。如果 partitionResolverType 属性中指定了值,则忽略 sqlConnectionString 和 stateConnectionString 属性。PartitionResolverType 属性返回的连接字符串将用于每个请求,为请求的其余部分连接到适当的服务器位置。如果连接字符串无效,ASPNET 将引发一个异常,该异常与当配置的服务器连接字符串无效时引发的异常相同。该属性用于在 SQL 或状态服务器模式下在多个后端节点上划分会话状态数据。
此属性是 NET Framework 20 版中的新属性。
默认值为空字符串。
regenerateExpiredSessionId
可选的 Boolean 属性。
指定当客户端指定了过期的会话 ID 时是否重新发出会话 ID。默认情况下,当启用了 regenerateExpiredSessionId 时,仅为 cookieless 模式重新发出会话 ID。有关更多信息,请参见 IsCookieless。
此属性是 NET Framework 20 版中的新属性。
默认值为 true。
sqlCommandTimeout
可选的 TimeSpan 属性。
指定使用 SQL Server 会话状态模式的 SQL 命令的持续时间超时(秒)。持续时间超时是 SQL 命令可以处于空闲状态的时间(秒),超过此时间之后,该命令将被取消。
此属性是 NET Framework 20 版中的新属性。
默认值为 0:00:30(30 秒)。
sqlConnectionString
可选的 String 属性。
为运行 SQL Server 的计算机指定连接字符串。该属性在 mode 属性设置为 SQLServer 值时是必需的。有关更多信息,请参见会话状态模式。
注意
若要在使用 SQLServer 模式时提高您的应用程序的安全性,请使用受保护的配置来加密配置的 sessionState 节,以帮助保护 sqlConnectionString 值。
默认值为 "data source=127001;Integrated Security=SSPI"。
stateConnectionString
可选的 String 属性。
指定远程存储会话状态的服务器名称或地址以及端口。端口值必须为 42424。当 mode 为 StateServer 值时,该属性是必需的。确保运行 ASPNET 状态服务的服务器是存储会话状态信息的远程服务器。该服务随 ASPNET 一起安装,默认情况下为 %SystemRoot%\MicrosoftNET\Framework\VersionNumber\aspnet_stateexe。有关更多信息,请参见会话状态模式。
注意
若要在使用 StateServer 模式时提高您的应用程序的安全性,请使用受保护的配置来加密配置的 <sessionState> 节,以帮助保护 stateConnectionString 值。
默认值为 "tcpip=127001:42424"。
stateNetworkTimeout
可选的 TimeSpan 属性。
指定 Web 服务器与状态服务器之间的 TCP/IP 网络连接可以处于空闲状态的时间(秒),超过此时间后,请求将被取消。该属性在 mode 属性设置为 StateServer 值时使用。
默认值为 10 秒。
timeout
可选的 TimeSpan 属性。
指定在放弃一个会话前该会话可以处于空闲状态的分钟数。对于进程内和状态服务器模式,timeout 属性不能设置为大于 525,601 分钟(1 年)的值。
会话 timeout 配置设置仅适用于 ASPNET 页。更改会话 timeout 值不会影响 ASP 页的会话超时时间。同样,更改 ASP 页的会话超时时间不会影响 ASPNET 页的会话超时时间。
默认值为 20 分钟。
useHostingIdentity
7
可选的 TimeSpan 属性。
指定在放弃一个会话前该会话可以处于空闲状态的分钟数。对于进程内和状态服务器模式,timeout 属性不能设置为大于 525,601 分钟(1 年)的值。
会话 timeout 配置设置仅适用于 ASPNET 页。更改会话 timeout 值不会影响 ASP 页的会话超时时间。同样,更改 ASP 页的会话超时时间不会影响 ASPNET 页的会话超时时间。
默认值为 20 分钟。
useHostingIdentity
可选的 Boolean 属性。
指定会话状态将恢复为宿主标识还是使用客户端模拟。
如果为 true,ASPNET 将使用下列进程凭据之一来连接会话状态存储区:
宿主进程;对于 Microsoft Internet 信息服务 [IIS] 5 和 51 版为 ASPNET,对于 Microsoft Windows Server 2003 则为 NETWORK SERVICE。
应用程序模拟标识,当使用了以下配置时使用此凭据:
<identity impersonate="true" userName="user" password="pwd" />
如果为 false,ASPNET 将使用目前与当前请求的操作系统线程关联的凭据来连接会话状态存储区。对于客户端模拟,ASPNET 将使用与浏览器协商的安全凭据来连接会话状态存储区。如果为 false,ASPNET 在连接会话状态存储区时不会恢复为进程标识或应用程序模拟标识。有关更多信息,请参见 ASPNET 模拟。
此属性是 NET Framework 20 版中的新属性。
默认值为 true。
注意
在 NET Framework 11 版中,如果 mode 属性设置为 SQLServer,并且客户端模拟有效,则 ASPNET 使用来自 ASPNET 客户端模拟的客户端凭据连接到运行 SQL Server 的计算机。
继承的属性
可选的属性。
由所有节元素继承的属性。
不存在websocket服务器间通信的概念。多服务器情景相当于一般B/S系统的多点负载均衡,关键问题确实是共享session,共享session的标准方案是通过session令牌从数据库或者统一的缓存服务器中存/取session,比如题主提到的Redis,而不是简单地利用java等语言/框架提供的基础session读写方案,那只适用于单服务器单站点。
Spring Session作为Spring社区官方推荐的一个比较简单快速的Java Web分布式session解决方案,帮我们搞定了长期以来比较蛋疼的session分布式的问题。
Spring Session解决的基本思路很简单,即将用户的session信息全部存放到一个redis数据库中,所有的session都从这个数据库拿。由于redis是一个内存数据库,数据信息读写是非常快速的。如此一来,多个Tomcat,共用一个redis数据库,即实现了session的共享问题。
访问Spring Session官方网站:
在百度中查询Spring Session即可找到Spring Session的官方站点。
目前版本为102,103版本处于snapshot状态。
Spring指出,Spring Session具有如下能力:
(1) API and implementations for managing a user's session
(2) HttpSession - allows replacing the HttpSession in an application container (ie Tomcat) neutral way
(2-1)Clustered Sessions - Spring Session makes it trivial to support clustered sessions without being tied to an application container specific solution
(2-2)Multiple Browser Sessions - Spring Session supports managing multiple users' sessions in a single browser instance (ie multiple authenticated accounts similar to Google)
(2-3)RESTful APIs - Spring Session allows providing session ids in headers to work with RESTful APIs
(3) WebSocket - provides the ability to keep the HttpSession alive when receiving WebSocket messages
对Spring Session有了基本了解之后,可以开始配置Maven的pomxml,导入SpringSession的jar包
Spring官方文档指出,要使用Spring Session,配置如下依赖即可:
<dependency>
<groupId>orgspringframeworksession</groupId>
<artifactId>spring-session-data-redis</artifactId>
<version>102RELEASE</version>
</dependency>
实际上,spring-session-data-redis并不是一个实际的jar包,只不过它配置了其他的四个依赖:
Spring-session-data-redis是一个空的包,我们可以从如下截图中看出。Spring-session-data-redis仅仅只有一个META-INF文件夹。它的作用就在于引入其他四个包。
当然,实际上你也可以不配置spring-session-data-redis,而直接配置实际上导入的类:
<!-- Redis -->
<dependency>
<groupId>orgspringframeworkdata</groupId>
<artifactId>spring-data-redis</artifactId>
<version>142RELEASE</version>
</dependency>
<dependency>
<groupId>redisclients</groupId>
<artifactId>jedis</artifactId>
<version>252</version>
</dependency>
<!-- Spring Session -->
<dependency>
<groupId>orgspringframeworksession</groupId>
<artifactId>spring-session</artifactId>
<version>102RELEASE</version>
</dependency>
<dependency>
<groupId>orgapachecommons</groupId>
<artifactId>commons-pool2</artifactId>
<version>22</version>
</dependency>
我们这里,首先,配置spring-data-redis和jedis,这样,就可以使用spring-data-redis框架,来实现访问redis数据库。
spring-data-redis是spring的一个子项目,和spring-session一样。spring-session要访问redis,这里spring-session依赖spring-data-redis,来实现操作reids数据库。
Spring Core、Spring Web需要配置4x版本。
当然,Spring Session还需要把Spring Web等常见的Spring包引入。Spring Session 102依赖Spring的版本为416以上,因此,3x版本的Spring是无法使用的:
可以从Maven Repository查看依赖情况:
此外,注意javaxservlet-api需要301版本以上。
配置application-contextxml文件
这里,我们以使用xml配置方式为例,当然也可以使用注解配置,详见SPring的官方例子(见参考资料)
备注:xml的配置方法官方给出了一个例子:
在application-contextxml文件中,加入:
<context:annotation-config/>
<bean class="orgspringframeworksessiondataredisconfigannotationwebhttpRedisHttpSessionConfiguration"/>
<bean id="poolConfig" class="redisclientsjedisJedisPoolConfig" />
<bean id="connectionFactory" class="orgspringframeworkdataredisconnectionjedisJedisConnectionFactory" p:host-name="${redishost}" p:port="${redisport}" p:password="${redispass}" p:pool-config-ref="poolConfig"/>
其中,${redishost}等即redis数据库的服务器地址,端口,密码等信息,放在properties文件中即可。
修改webxml,加入Spring Session的Filter
在webxml文件中,加入:
<filter>
<filter-name>springSessionRepositoryFilter</filter-name>
<filter-class>orgspringframeworkwebfilterDelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSessionRepositoryFilter</filter-name>
<url-pattern>/</url-pattern>
</filter-mapping>
这样,所有的请求,都会被DelegatingFilterProxy处理,实际上,DelegatingFilterProxy会找到springSessionRepositoryFilter,创建它。每一次的请求还是由springSessionRepositoryFilter来过滤的。
The DelegatingFilterProxy will look up a Bean by the name of springSessionRepositoryFilter and cast it to a Filter For every request that DelegatingFilterProxy is invoked, the springSessionRepositoryFilter will be invoked
这里,Spring加入了一个Filter,其本质是:对每一个请求的request进行了一次封装。那么,在Controller里面拿出的request实际上是封装后的request,
调用requestgetSession()的时候,实际上拿到是Spring封装后的session。这个session则存储在redis数据库中。
访问Web项目,查看session
访问Web项目,这个时候,使用redis-cli进入redis命令操作界面,在使用keys 可以查看所有的key:
第一个是当前访问的用户的session信息,第二个保存的是过期的时间。
可以查看session的详细内容如下:
可以看出,session对象被序列化后存入。因此,所有放入session的对象,都要实现Serializable接口。比如,我将所有的用户信息,封装到一个Authentication对象,那么
这对象就必须实现Serializable接口:
补充一下:
如果要设置Session的过期时间,通常我们会在webxml文件中进行设置:
但是,使用Spring Session托管session后,这里的设置将会失效。我们要专门为Spring Session进行设置:
将application-contextxml,即步骤4中的的RedisHttpSessionConfiguration,设置其maxInactiveIntervalInSeconds属性即可。注意,maxInactiveIntervalInSeconds的的单位是秒! 如下将设置session为10分钟过期!
<bean class="orgspringframeworksessiondataredisconfigannotationwebhttpRedisHttpSessionConfiguration">
<property name="maxInactiveIntervalInSeconds" value="600"></property>
</bean>
一、术语session
在我的经验里,session这个词被滥用的程度大概仅次于transaction,更加有趣的是transaction与session在某些语境下的含义是相同的。
session,中文经常翻译为会话,其本来的含义是指有始有终的一系列动作/消息,比如打电话时从拿起电话拨号到挂断电话这中间的一系列过程可以称之为一个session。有时候我们可以看到这样的话"在一个浏览器会话期间,",这里的会话一词用的就是其本义,是指从一个浏览器窗口打开到关闭这个期间①。最混乱的是"用户(客户端)在一次会话期间"这样一句话,它可能指用户的一系列动作(一般情况下是同某个具体目的相关的一系列动作,比如从登录到选购商品到结账登出这样一个网上购物的过程,有时候也被称为一个transaction),然而有时候也可能仅仅是指一次连接,也有可能是指含义①,其中的差别只能靠上下文来推断②。
然而当session一词与网络协议相关联时,它又往往隐含了"面向连接"和/或"保持状态"这样两个含义,"面向连接"指的是在通信双方在通信之前要先建立一个通信的渠道,比如打电话,直到对方接了电话通信才能开始,与此相对的是写信,在你把信发出去的时候你并不能确认对方的地址是否正确,通信渠道不一定能建立,但对发信人来说,通信已经开始了。"保持状态"则是指通信的一方能够把一系列的消息关联起来,使得消息之间可以互相依赖,比如一个服务员能够认出再次光临的老顾客并且记得上次这个顾客还欠店里一块钱。这一类的例子有"一个TCP session"或者"一个POP3 session"③。
而到了web服务器蓬勃发展的时代,session在web开发语境下的语义又有了新的扩展,它的含义是指一类用来在客户端与服务器之间保持状态的解决方案④。有时候session也用来指这种解决方案的存储结构,如"把xxx保存在session里"⑤。由于各种用于web开发的语言在一定程度上都提供了对这种解决方案的支持,所以在某种特定语言的语境下,session也被用来指代该语言的解决方案,比如经常把Java里提供的javaxservlethttpHttpSession简称为session⑥。
鉴于这种混乱已不可改变,本文中session一词的运用也会根据上下文有不同的含义,请大家注意分辨。
在本文中,使用中文"浏览器会话期间"来表达含义①,使用"session机制"来表达含义④,使用"session"表达含义⑤,使用具体的"HttpSession"来表达含义⑥
二、HTTP协议与状态保持
HTTP协议本身是无状态的,这与HTTP协议本来的目的是相符的,客户端只需要简单的向服务器请求下载某些文件,无论是客户端还是服务器都没有必要纪录彼此过去的行为,每一次请求之间都是独立的,好比一个顾客和一个自动售货机或者一个普通的(非会员制)大卖场之间的关系一样。
然而聪明(或者贪心?)的人们很快发现如果能够提供一些按需生成的动态信息会使web变得更加有用,就像给有线电视加上点播功能一样。这种需求一方面迫使HTML逐步添加了表单、脚本、DOM等客户端行为,另一方面在服务器端则出现了CGI规范以响应客户端的动态请求,作为传输载体的HTTP协议也添加了文件上载、cookie这些特性。其中cookie的作用就是为了解决HTTP协议无状态的缺陷所作出的努力。至于后来出现的session机制则是又一种在客户端与服务器之间保持状态的解决方案。
让我们用几个例子来描述一下cookie和session机制之间的区别与联系。笔者曾经常去的一家咖啡店有喝5杯咖啡免费赠一杯咖啡的优惠,然而一次性消费5杯咖啡的机会微乎其微,这时就需要某种方式来纪录某位顾客的消费数量。想象一下其实也无外乎下面的几种方案:
1、该店的店员很厉害,能记住每位顾客的消费数量,只要顾客一走进咖啡店,店员就知道该怎么对待了。这种做法就是协议本身支持状态。
2、发给顾客一张卡片,上面记录着消费的数量,一般还有个有效期限。每次消费时,如果顾客出示这张卡片,则此次消费就会与以前或以后的消费相联系起来。这种做法就是在客户端保持状态。
3、发给顾客一张会员卡,除了卡号之外什么信息也不纪录,每次消费时,如果顾客出示该卡片,则店员在店里的纪录本上找到这个卡号对应的纪录添加一些消费信息。这种做法就是在服务器端保持状态。
由于HTTP协议是无状态的,而出于种种考虑也不希望使之成为有状态的,因此,后面两种方案就成为现实的选择。具体来说cookie机制采用的是在客户端保持状态的方案,而session机制采用的是在服务器端保持状态的方案。同时我们也看到,由于采用服务器端保持状态的方案在客户端也需要保存一个标识,所以session机制可能需要借助于cookie机制来达到保存标识的目的,但实际上它还有其他选择。
三、理解cookie机制
cookie机制的基本原理就如上面的例子一样简单,但是还有几个问题需要解决:"会员卡"如何分发;"会员卡"的内容;以及客户如何使用"会员卡"。
正统的cookie分发是通过扩展HTTP协议来实现的,服务器通过在HTTP的响应头中加上一行特殊的指示以提示浏览器按照指示生成相应的cookie。然而纯粹的客户端脚本如JavaScript或者VBScript也可以生成cookie。
而cookie的使用是由浏览器按照一定的原则在后台自动发送给服务器的。浏览器检查所有存储的cookie,如果某个cookie所声明的作用范围大于等于将要请求的资源所在的位置,则把该cookie附在请求资源的HTTP请求头上发送给服务器。意思是麦当劳的会员卡只能在麦当劳的店里出示,如果某家分店还发行了自己的会员卡,那么进这家店的时候除了要出示麦当劳的会员卡,还要出示这家店的会员卡。
cookie的内容主要包括:名字,值,过期时间,路径和域。
其中域可以指定某一个域比如googlecom,相当于总店招牌,比如宝洁公司,也可以指定一个域下的具体某台机器比如wwwgooglecom或者frooglegooglecom,可以用飘柔来做比。
路径就是跟在域名后面的URL路径,比如/或者/foo等等,可以用某飘柔专柜做比。
路径与域合在一起就构成了cookie的作用范围。
如果不设置过期时间,则表示这个cookie的生命期为浏览器会话期间,只要关闭浏览器窗口,cookie就消失了。这种生命期为浏览器会话期的cookie被称为会话cookie。会话cookie一般不存储在硬盘上而是保存在内存里,当然这种行为并不是规范规定的。如果设置了过期时间,浏览器就会把cookie保存到硬盘上,关闭后再次打开浏览器,这些cookie仍然有效直到超过设定的过期时间。
存储在硬盘上的cookie可以在不同的浏览器进程间共享,比如两个IE窗口。而对于保存在内存里的cookie,不同的浏览器有不同的处理方式。对于IE,在一个打开的窗口上按Ctrl-N(或者从文件菜单)打开的窗口可以与原窗口共享,而使用其他方式新开的IE进程则不能共享已经打开的窗口的内存cookie;对于Mozilla Firefox08,所有的进程和标签页都可以共享同样的cookie。一般来说是用javascript的windowopen打开的窗口会与原窗口共享内存cookie 。浏览器对于会话cookie的这种只认cookie不认人的处理方式经常给采用session机制的web应用程序开发者造成很大的困扰。
下面就是一个goolge设置cookie的响应头的例子
HTTP/11 302 Found
Location: http://wwwgooglecom/intl/zh-CN/
Set-Cookie: PREF=ID=0565f77e132de138:NW=1:TM=1098082649:LM=1098082649:S=KaeaCFPo49RiA_d8; expires=Sun, 17-Jan-2038 19:14:07 GMT; path=/; domain=googlecom
Content-Type: text/html
存的页面:
Session["你取的名字"] = 你要存进去的对象;
取的页面:
你存进去的对象 = Sesson["你取的名字"] as 对象类型;
3、session
session的用法,即HttpSession类型的用法
(1)得到一个会话对象:HttpSession hs = requestgetSession(true);
(2)给会话对象添加属性:hssetAttribute(String name,Object val);
(3)得到某个属性:String name = hsgetAttribute(String name);
(4)删除某个属性:hsremoveAttribute(String name);
(5)得到服务器分配给该会话的ID:String id = hsgetId();
(6)删除全部的会话属性:hssetMaxInactiveInterval(0);这个方法可以用来安全注销,是最安全的
session在一个会话中都是有效的,而在同一个会话中你可以访问多个servlet,也就是说在不同的servlet中session是相同的,是可以共享的。
共享办法:在servlet中先得到session,即
HttpSession
session
=
requestgetSession();再使用session,在jsp也页面中实现是可以的,因为jsp中内置了session对象,所以不用自己定义,但是在serlvet中得自己获取。
Session:用户访问某个网站时,web服务器就会在服务器的内存中为该浏览器分配一个空间,这个空间是被浏览器独占的。该空间就称其为
Session空间
,用户通过浏览器访问服务器,再到浏览器退出访问这段时间叫做
session会话
,这个会话时间通常为30min(可以手动修改)。
注:以下内容基于以tomcat作为web服务器
session是http协议无状态问题的常见解决方案之一 ,用户登录成功之后,把用户信息保存到session(默认储存在服务端的内存)。对于浏览器发起的HTTP请求,可以根据session中是否存在用户信息判断用户是否登录,也方便业务逻辑中获取当前会话用户信息。
服务端创建session时,会生成JSESSIONID作为唯一标识,并将一个key为"JSESSIONID"的cookie返回给前端(前提是浏览器支持cookie),之后,根据浏览器发起请求时携带的JSESSIONID判断用户身份。
tomcat的JSESSIONID生成的机制是一个随机数加时间加上jvm的id值,jvm的id值会根据服务器的硬件信息计算得来,因此不同jvm的id值都是唯一的。
当后端显式调用requestgetSession()或requestgetSession(true)时,会创建session(注意:需要显式调用,spring或tomcat不会自动生成)
requestgetSession()有个重载方法requestgetSession(boolean create)
create为true表示,若可以根据前端cookie中的JSESSIONID找到对应的session,则返回该session,否则重新创建一个session,并把新的JSESSIONID返回给前端。
create为false表示,若可以根据前端cookie中的JSESSIONID找到对应的session,则返回该session,否则返回null。
requestgetSession()等价于requestgetSession(true)
session是http协议无状态问题的常见解决方案之一,但在用户量大,或者分布式系统等场景下,该方案有许多弊端。
1session默认储存在服务端内存,用户量大时占用内存多
2需要处理session共享,用户在一台服务器登录后,集群内其他机器没有该用户的session,需要用某些方式实现session共享,并保持一致性,即同步修改所有机器的session
3同样的数据保存在多台服务器,数据冗余
4如果使用cookie发送JSESSIONID到服务端,则不支持跨域请求
5如果浏览器cookie被禁用,就需要用其余方式保存JSESSIONID
6如果session没有持久化,重启服务器后session就没了
修改负载均衡策略为按ip负载(即同一个ip只访问同一台机器),这样就绕开了session共享的问题(默认策略一般是轮询)
弊端
按ip负载策略和轮询策略,本质上是按用户负载和按请求负载,这两种策略的区别在于, 按请求负载更加均衡 ,比如A、B服务器都有20个用户,A服务器的20个用户相比B服务器更加活跃,那么A服务器的压力就更大。
集成spring-session-redis(网上很多教程),先集成redis,然后在启动类加上@EnableRedisHttpSession注解,这样操作session时,会自动把数据持久化到redis集群
tomcat 配置session复制(未做了解)
同时使用token+session,token用于接口鉴权,session用于保存用户信息。
增加一个拦截器,在找不到session时,根据token反解析出用户信息,然后存入session。
(一般公司会有统一的用户中心,提供校验token并返回用户身份的接口)
严格来说,本方案不算是session共享方案,因为不同服务端的session id不一致,每次请求不同服务器,带上来的session id在本服务器找不到,就产生新的session,直到有效期到期才销毁,严重浪费内存
1最常见的方式: cookie
2如果cookie被禁止,可以用URL重写技术,把session id拼接到URL中
3在表单添加隐藏字段,提交表单时把session id传到服务端
先说结论:如果服务器是集群,且没有配置会话保持,同一个浏览器窗口的JSESSIONID就会变化
用户在A服务器登录成功后,A服务器把key为JSESSIONID的cookie返回给用户,然后携带该JSESSIONID请求B服务器,B服务器找不到该JSESSIONID对应的session,就会创建新的session,把新的JSESSIONID返回给用户。
取决于JSESSIONID的保存方式
如果保存在cookie,要看cookie有没有设置有效期,如果没设有效期,重启浏览器cookie就没了,如果设了有效期,重启浏览器cookie还在。
如果使用URL重写或表单隐藏字段的方式,要看JSESSION具体保存在哪
对于单机应用,JSESSIONID可以用于校验接口(类似于token),后端如果能根据JSESSIONID获取到对应session(即requestgetSession(false)不为空),说明该请求有效。但是服务器一旦重启,用户登录就失效了,因为session放在内存中。
如果使用token做接口校验,不仅可以适用于分布式应用,后端重启也不会影响用户的登录态。
0条评论