session理解

本文详细解析Web开发中的Session与Cookie机制,包括它们的定义、工作原理、区别与联系,以及如何在实际项目中应用。重点讨论了Session在何时创建、何时删除、如何防止混乱以及在浏览器关闭时的处理方式。此外,还涉及了Session的用法、存储信息的注意事项以及常见的问题解决策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    作为一名WEB开发程序员,对session的理解是最基础的,但是现状是WEB程序员遍地都是,随便一划拉一大把,不过估计能把session能透彻理解的人应该不是很多,起码我之前对此是知之甚少,偶然看到的一个关于session的文章,经过适当整理,特拿来与大家分享,因为时间太久,文章出处已然记不清楚,无法附上,请原作理解,若有必要我会删除,谢谢!

目 录
一、Session
二、Cookies
三、Cookies机制
四、Session机制
五、Cookies机制与Session机制的区别和联系
六、常见问题
七、Session的用法

Session是WEB上有效的信息交互手段,因其使用方便、稳定、安全、可靠而被众多WEB开发者所认知。尤其在互联网身份验证、网上电子购物等方面的应用更为广泛。下面就着重来介绍下Session。

一、Session
Session,在汉语中表示通话、会话、对话(期)、话路[对谈时间]的意思,其本来的含义一个终端用户与交互系统进行通信的时间(间隔),通常是指从注册(进入系统)到注销(退出系统)之间所经过的时间。比如打电话时从拿起电话拨号到挂断电话这中间的一系列过程可以称之为一个Session。有时候我们可以看到这样的话“在一个浏览器会话期间,…”,这里的会话一词用的就是这个意思,是指从一个浏览器窗口打开到关闭这个期间。Session在我们的网络应用中就是一种客户端与服务器端保持状态的解决方案,有时候Session也用来指这种解决方案的存储结构,
Session对象,就是客户端浏览器与服务器之间建立的互动信息状态。每一个不同的用户连接将得到不同的Session,也就是说Session与用户之间是一种一对一的关系。Session在用户进入网站时由服务器自动产生,并在用户正常离开站点时释放。使用Session的好处就在于,可以将很多与用户相关的信息,例如用户的帐号、昵称等保存到Session中;利用Session,可以跟踪用户在网站上的活动。例如:当你上网进入一个网站时,如果你没有登陆,无论你访问哪几个页面都会跳转回登陆页。还有就是你在购物时,不可能把你的东西放到别人的购物车里去,这就得用一个信息变量来判断!
如果能够提供一些按需生成的动态信息会使web变得更加有用,就像给有线电视加上点播功能一样。这种需求一方面迫使HTML逐步添加了表单、脚本、DOM 等客户端行为,另一方面在服务器端则出现了CGI规范以响应客户端的动态请求,作为传输载体的HTTP协议也添加了文件上载、cookie这些特性。其中 cookie的作用就是为了解决HTTP协议无状态的缺陷所作出的努力。至于后来出现的Session机制则是又一种在客户端与服务器之间保持状态的解决方案。

二、Cookies
Cookie是WEB上最常用的跟踪用户会话方式,当  Cookie被禁止后,一般都用URL重写来跟踪会话。Cookie是一种由服务器发送给客户的片段信息,存储在客户环境中,并在客户所有的对服务器的请求中都要发回它。就好比我们在用IE登陆某个电子购物商城时,IE在得到商品列表页面的 同时还收到Set-Cookie应答头信息,我们打开一个Cookie文件,我们所看到的格式一般都是:
Cookie:NAME=VALUE;Comment=COMMENT;Domain=DOMAINNMAM;Max-age=SECONDS;Path=PATH;secure;Version=1*DIGIT
其中NAME值对(值对间用分号分隔)是必须的,其余都是可选的。最重要的信息当然也在所必须的值对里了,VALUE是NAME的值,也是这个 Cookie的标识,Max-age定义了Cookie的最长生存时间,其它几个可选值对可参阅http://www.faqs.org/rfcs /rfc2109.html。当我们选购了某种商品,向服务器发送选购清单时,会自动在你的请求信息头里加上NAME值对,如果Cookie被禁止,则用 URL重写方式在URL请求地址上附加NAME值对。当Web服务器收到这个请求后,会检查该Cookie是否存在,然后相应的跟踪会话。从以上分析不难理解,其实Web服务器跟踪会话就靠Set-Cookie头信息,跟踪NAME值对进行身份验证。假如我们用非Web终端接收Web服务器的响应信息,从中解析出Cookie头信息,当再次向Web服务器发送请求时附加上解析出的Cookie信息,Web服务器据此不就可以进行身份认证了吗?
Cookies中文是饼干的意思,对于为何引用Cookies,从网上查找了一些资料:
在浏览器与WEB服务器之间是使用HTTP协议进行通信的,当某个用户发出页面请求时,WEB服务器只是简单的进行响应,然后就关闭与该用户的连接。因此当一个请求发送到WEB服务器时,无论其是否是第一次来访,服务器都会把它当作第一次来对待,这样的不好之处可想而知。为了弥补这个缺陷,Netscape开发出了cookie这个有效的工具来保存某个用户的识别信息,因此人们昵称为“小甜饼”。cookies是一种WEB服务器通过浏览器在访问者的硬盘上存储信息的手段:Netscape Navigator使用一个名为cookies.txt本地文件保存从所有站点接收的Cookie信息;而IE浏览器把Cookie信息保存在类似于 c:\Internet 临时文件\的目录下。当用户再次访问某个站点时,服务端将要求浏览器查找并返回先前发送的Cookie信息,来识别这个用户。Cookies给网站和用户带来的好处:
(1)、Cookie能使站点跟踪特定访问者的访问次数、最后访问时间和访问者进入站点的路径
(2)、Cookie能告诉在线广告商广告被点击的次数,从而可以更精确的投放广告
(3)、Cookie有效期限未到时,Cookie能使用户在不键入密码和用户名的情况下进入曾经浏览过的一些站点
       (4)、Cookie能帮助站点统计用户个人资料以实现各种各样的个性化服务,其实,cookie的作用就是为了解决HTTP协议无状态的缺陷所作的努力.

三.Cookie机制
Cookie机制采用的是在客户端保持状态的方案。
Cookie机制,就是当服务器对访问它的用户生成了一个Session的同时服务器通过在HTTP的响应头中加上一行特殊的指示以提示浏览器按照指示生成相应的cookie,保存在客户端,里面记录着用户当前的信息,当用户再次访问服务器时,浏览器检查所有存储的cookie,如果某个cookie所声明的作用范围大于等于将要请求的资源所在的位置也就是对应的Cookie文件。 若存在,则把该cookie附在请求资源的HTTP请求头上发送给服务器,例如:当我们登陆了一个网站,并且填写了有关资料,以本站会员的名义登陆上了有关网页,这时你把浏览器关闭,再重启进入该网站的某一个页面时是以你登陆过的会员进去的,当然,不是所有网站都是这样,我们知道,cookie的保存有临时性的和持久性的,大多都是临时性的,也就是cookie只保存在客户端的内存中,而没有保存在硬盘上,当关闭浏览器,cookie也就销毁。以下是有关 cookie机制的一些具体说明:
cookie的内容主要包括:名字,值,过期时间,路径和域。
其中域可以指定某一个域比如.google.com,相当于总店招牌,比如宝洁公司,也可以指定一个域下的具体某台机器比如www.google.com或者froogle.google.com,可以用飘柔来做比。
路径就是跟在域名后面的URL路径,比如/或者/foo等等,可以用某飘柔专柜做比。路径与域合在一起就构成了cookie的作用范围。
如果不设置过期时间,则表示这个cookie的生命期为浏览器会话期间,只要关闭浏览器窗口,cookie就消失了。这种生命期为浏览器会话期的 cookie被称为会话cookie。会话cookie一般不存储在硬盘上而是保存在内存里,当然这种行为并不是规范规定的。如果设置了过期时间,浏览器就会把cookie保存到硬盘上,关闭后再次打开浏览器,这些cookie仍然有效直到超过设定的过期时间。
存储在硬盘上的cookie可以在不同的浏览器进程间共享,比如两个IE窗口。而对于保存在内存里的cookie,不同的浏览器有不同的处理方式。对于微软的IE浏览器,在一个打开的窗口上按Ctrl-N(或者从文件菜单)打开的窗口可以与原窗口共享,而使用其他方式新开的IE进程则不能共享已经打开的窗口的内存cookie;对于火狐狸firefox浏览器,所有的进程和标签页都可以共享同样的cookie。一般来说是用javascript的 window.open打开的窗口会与原窗口共享内存cookie。浏览器对于会话cookie的这种只认cookie不认人的处理方式经常给采用 Session机制的web应用程序开发者造成很大的困扰。

四、Session机制
Session机制采用的是在服务器端保持状态的方案。
当用户访问到一个服务器,服务器就要为该用户创建一个SESSION,在创建这个SESSION的时候,服务器首先检查这个用户发来的请求里是否包含了一个SESSIONID,如果包含了一个SESSIONID则说明之前该用户已经登陆过并为此用户创建过SESSION,那服务器就按照这个 SESSIONID把这个SESSION在服务器的内存中查找出来(如果查找不到,就有可能为他新创建一个),如果客户端请求里不包含有 SESSIONID,则为该客户端创建一个SESSION并生成一个与此SESSION相关的SESSIONID。这个SESSIONID是唯一的、不重复的、不容易找到规律的字符串,这个SESSIONID将被在本次响应中返回到客户端保存,而保存这个SESSIONID的正是COOKIE,这样在交互过程中浏览器可以自动的按照规则把这个标识发送给服务器。
我们知道在IE中,我们可以在工具的internet选项中把COOKIE禁止,那么会不会出现把客户端的COOKIE禁止了,SESSIONID就无法再用了呢?找了一些资料说明,可以有其他机制在COOKIE被禁止时仍然能够把Session id传递回服务器。经常被使用的一种技术叫做URL重写,就是把Session id直接附加在URL路径的后面一种是作为URL路径的附加信息,表现形式为:
http://…./xxx;jSession=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764;
另一种是作为查询字符串附加在URL后面,表现形式为:
http://…../xxx?jSession=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764
还有一种就是表单隐藏字段。就是服务器会自动修改表单,添加一个隐藏字段,以便在表单提交时能够把Session id传递回服务器。这里就不介绍了。
我们常说的在一个IE被打开是创建一个Session,当关闭IE时Session也就被删除,事实上,除非程序通知服务器删除Session,否则 Session会被服务器一直保留,直到Session的失效时间到了自动删除。服务器不知道IE被关闭,IE不会主动在其关闭之前通知服务器它将要关闭。程序一般都是在用户做注销时删除Session。我们产生这种错觉的原因是:一般Session机制都使用cookie来保存Session id,而一旦关闭IE浏览器,Session id就不存在了,再连接服务器时找不到原来的Session了.如果服务器设置的cookie被保存到硬盘上,或者使用某种手段改写浏览器发出的 HTTP请求头,把原来的Session id发送给服务器,则再次打开浏览器仍然能够找到原来的Session。恰恰是由于关闭浏览器不会导致Session被删除,迫使服务器为seesion 设置了一个失效时间,当距离客户端上一次使用Session的时间超过这个失效时间时,服务器就可以认为客户端已经停止了活动,才会把Session删除以节省存储空间。
一般情况下,Session都是存储在内存里,当服务器进程被停止或者重启的时候,内存里的Session也会被清空,如果设置了Session的持久化特性,服务器就会把Session保存到硬盘上,当服务器进程重新启动或这些信息将能够被再次使用。

五、cookie机制与Session机制的区别和联系
具体来说cookie机制采用的是在客户端保持状态的方案,而Session机制采用的是在服务器端保持状态的方案。同时我们也看到,由于在服务器端保持状态的方案在客户端也需要保存一个标识,所以Session机制可能需要借助于cookie机制来达到保存标识的目的,但实际上还有其他选择。例如,我们经常用到的会员卡,也就相当于这种情况。消费到了一定程度就有奖,就如下面例子说明:
1.发给顾客一张卡片,上面记录着消费的数量,一般还有个有效期限。每次消费时,如果顾客出示这张卡片,则此次消费就会与以前或以后的消费相联系起来。这种做法就是在客户端保持状态。
2、发给顾客一张会员卡,除了卡号之外什么信息也不纪录,每次消费时,如果顾客出示该卡片,则店员在店里的纪录本上找到这个卡号对应的纪录添加一些消费信息。这种做法就是在服务器端保持状态。
以下是一些关于两者的区别与联系:
具体来说cookie机制采用的是在客户端保持状态的方案。它是在用户端的会话状态的存贮机制,他需要用户打开客户端的cookie支持。cookie的作用就是为了解决HTTP协议无状态的缺陷所作的努力.而Session机制采用的是一种在客户端与服务器之间保持状态的解决方案。同时我们也看到,由于采用服务器端保持状态的方案在客户端也需要保存一个标识,所以Session机制可能需要借助于cookie机制来达到保存标识的目的。而Session 提供了方便管理全局变量的方式。
Session是针对每一个用户的,变量的值保存在服务器上,用一个Session来区分是哪个用户Session变量,这个值是通过用户的浏览器在访问的时候返回给服务器,当客户禁用cookie时,这个值也可能设置为由get来返回给服务器。
就安全性来说:当你访问一个使用Session 的站点,同时在自己机子上建立一个cookie,建议在服务器端的SESSION机制更安全些.因为它不会任意读取客户存储的信息。
正统的cookie分发是通过扩展HTTP协议来实现的,服务器通过在HTTP的响应头中加上一行特殊的指示以提示浏览器按照指示生成相应的cookie。
从网络服务器观点看所有HTTP请求都独立于先前请求。就是说每一个HTTP响应完全依赖于相应请求中包含的信息.
状态管理机制克服了HTTP的一些限制并允许网络客户端及服务器端维护请求间的关系。在这种关系维持的期间叫做会话(Session)。
Cookies是服务器在本地机器上存储的小段文本并随每一个请求发送至同一个服务器。IETF RFC 2965 HTTP State Management Mechanism 是通用cookie规范。网络服务器用HTTP头向客户端发送cookies,在客户终端,浏览器解析这些cookies并将它们保存为一个本地文件,它会自动将同一服务器的任何请求缚上这些cookies 。
来看一下Tomcat是如何实现web应用程序之间session的隔离的,从Tomcat设置的cookie路径来看,它对不同的应用程序设置的 cookie路径是不同的,这样不同的应用程序所用的session id是不同的,因此即使在同一个浏览器窗口里访问不同的应用程序,发送给服务器的session id也可以是不同的。

六、常见问题
1、Session在何时被创建
Session在有客户端访问时就被创建,然而事实是直到某server端程序调用 HttpServletRequest.getSession(true)这样的语句时才被创建,注意如果JSP没有显示的使用 <%@page Session=”false”%> 关闭Session,则JSP文件在编译成Servlet时将会自动加上这样一条语句HttpSession Session = HttpServletRequest.getSession(true);这也是JSP中隐含的Session对象的来历。由于Session会消耗内存资源,因此,如果不打算使用Session,应该在所有的JSP中关闭它。
2、Session何时被删除
综合前面的讨论,Session在下列情况下被删除:
a.程序调用HttpSession.invalidate();
b.距离上一次收到客户端发送的Session id时间间隔超过了Session的超时设置;
c.服务器进程被停止(非持久Session)。
3、如何做到在浏览器关闭时删除Session
严格的讲,做不到这一点。可以做一点努力的办法是在所有的客户端页面里使用javascript代码window.oncolose来监视浏览器的关闭动作,然后向服务器发送一个请求来删除Session。但是对于浏览器崩溃或者强行杀死进程这些非常规手段仍然无能为力。
4、有个HttpSessionListener是怎么回事
你可以创建这样的listener去监控Session的创建和销毁事件,使得在发生这样的事件时你可以做一些相应的工作。注意是Session的创建和销毁动作触发listener,而不是相反。类似的与HttpSession有关的listener还有 HttpSessionBindingListener,HttpSessionActivationListener和 HttpSessionAttributeListener。
5、存放在Session中的对象必须是可序列化的吗
不是必需的。要求对象可序列化只是为了Session能够在集群中被复制或者能够持久保存或者在必要时server能够暂时把Session交换出内存。在Weblogic Server的Session中放置一个不可序列化的对象在控制台上会收到一个警告。
6、开两个浏览器窗口访问应用程序会使用同一个Session还是不同的Session
对Session来说是只认id不认人,因此不同的浏览器,不同的窗口打开方式以及不同的cookie存储方式都会对这个问题的答案有影响。
7、如何防止用户打开两个浏览器窗口操作导致的Session混乱
这个问题与防止表单多次提交是类似的,可以通过设置客户端的令牌来解决。就是在服务器每次生成一个不同的id返回给客户端,同时保存在Session里,客户端提交表单时必须把这个id也返回服务器,程序首先比较返回的id与保存在Session里的值是否一致,如果不一致则说明本次操作已经被提交过了。可以参看《J2EE核心模式》关于表示层模式的部分。需要注意的是对于使用javascript window.open打开的窗口,一般不设置这个id,或者使用单独的id,以防主窗口无法操作,建议不要再window.open打开的窗口里做修改操作,这样就可以不用设置。
8、为什么Session不见了
排除Session正常失效的因素之外,服务器本身的可能性应该是微乎其微的;理论上防火墙或者代理服务器在cookie处理上也有可能会出现问题。出现这一问题的大部分原因都是程序的错误,最常见的就是在一个应用程序中去访问另外一个应用程序。
9、服务器关掉后,当前Session会丢掉吗
这个取决于你使用什么样的web服务器以及web服务器是如何配置的。tomcat在shutdown前默认会自动将Session保存到指定的目录中,重新启动是重新加载,因此tomcat重新启动后,Session是可以继续使用的。此外,你还何以将Session保存到数据库中,这个要在 server.xml中配置。
10、Cookie的过期和Session的超时有什么区别
会话的超时由服务器来维护,它不同于Cookie的失效日期。首先,会话一般基于驻留内存的cookie不是持续性的cookie,因而也就没有截至日期。即使截取到JSESSION cookie,并为它设定一个失效日期发送出去。浏览器会话和服务器会话也会截然不同。

七、Session的用法
Session 对象
可以使用 Session 对象存储特定用户会话所需的信息。这样,当用户在应用程序的 Web 页之间跳转时,存储在 Session 对象中的变量将不会丢失,而是在整个用户会话中一直存在下去。
当用户请求来自应用程序的 Web 页时,如果该用户还没有会话,则 Web 服务器将自动创建一个 Session 对象。当会话过期或被放弃后,服务器将终止该会话。
Session 对象最常见的一个用法就是存储用户的首选项。例如,如果用户指明不喜欢查看图形,就可以将该信息存储在 Session 对象中。
注意:会话状态仅在支持 cookie 的浏览器中保留。
语法
Session.collection|property|method
集合
Contents 包含已用脚本命令添加到会话中的项目。
StaticObjects 包含通过 <OBJECT> 标记创建的并给定了会话作用域的对象。
属性
CodePage 将用于符号映射的代码页。
LCID 现场标识。
SessionID 返回用户的会话验证。
Timeout 应用程序会话状态的超时时限,以分钟为单位。
方法
Abandon 该方法破坏 Session 对象并释放其资源。
事件
asa 文件中声明下列事件的脚本。
Session_OnEnd
Session_OnStart
注释
您可以在 Session 对象中存储值。存储在 Session 对象中的信息在会话及会话作用域内有效。

说实话,读了一遍,没有完全看懂,只因为没有做过这样的项目,希望以后做有关移动互联网的地项目。

摘自: http://www.cnblogs.com/literoad/archive/2012/05/13/2498528.html
import { Client } from '@stomp/stompjs'; import SockJS from 'sockjs-client'; // npm remove stompjs // npm install @stomp/stompjs sockjs-client --save export default { connect() { return new Promise((resolve, reject) => { const socket = new SockJS('http://10.228.73.15:7788/websocket'); const stompClient = new Client({ webSocketFactory: () => socket, debug: () => { // 禁用调试输出,或根据需要处理 }, reconnectDelay: 5000, heartbeatIncoming: 4000, heartbeatOutgoing: 4000, }); stompClient.onConnect = (frame) => { console.log('Connected:', frame); resolve(stompClient); // 连接成功后立即订阅个人主题 // stompClient.subscribe(`/topic/commandOutput/${userId}`, (message) => { // console.log(1,message) // }); }; stompClient.onStompError = (error) => { console.error('Connection error:', error); reject(error); }; stompClient.activate(); }); } };<template> <div> <span style="display: flex; justify-content: center; margin-bottom: 8px"> <img alt="Vue logo" src="../assets/logo.png" style="width: 90px;"> </span> <span style="display: flex; justify-content: center; margin-bottom: 8px"> 当前登录用户: <input v-model="userId" placeholder="请输入p13" @keyup.enter="connectWebSocket"> <button @click="connectWebSocket" style="margin-left: 10px;">登录</button> </span> <span style="display: flex; justify-content: center"> <input ref="commandInput" v-model="currentCommand" style="width: 600px" placeholder="输入任意命令(如:ipconfig / dir)" :disabled="isExecuting" @keyup.enter="sendCommand" > <button @click="sendCommand" style="margin-left: 10px;" :disabled="isExecuting">执行命令</button> <button @click="abortCommand" style="margin-left: 10px; background: #ff4d4f" :disabled="!isExecuting" > 中止命令 </button> </span> <div style="display: flex"> <div style="margin-top: 20px; width: 30%;"> <h3 style="text-align: center">已执行命令</h3> <div style="height: 482px; overflow-y: auto; background: #f8f8f8;"> <div v-for="(msg, index) in messages" :key="index" style="margin-top: 8px; margin-left: 8px; border-radius: 4px; overflow-y: auto;" >  </div> </div> </div> <div style="padding: 20px; width: 70%"> <h3 style="text-align: center">实时命令输出</h3> <pre ref="outputPre" style="background: #282c34; color: #fff; padding: 15px; border-radius: 4px; height: 450px; overflow-y: auto" >  </pre> </div> </div> </div> </template> <script> import websocket from '@/utils/websocket' export default { name: 'HelloWorld', props: { msg: String }, data() { return { currentCommand: '', messages: [], currentOutput: '', stompClient: null, index: 1, userId: '', isExecuting: false // 控制命令是否正在执行 }; }, methods: { async connectWebSocket() { alert("登录成功"); try { this.stompClient = await websocket.connect(this.userId); this.$nextTick(() => { this.$refs.commandInput.focus(); // 命令结束后重新聚焦到输入框 }); const subscription = this.stompClient.subscribe(`/topic/commandOutput/${this.userId}`, (message) => { const output = message.body; if (output.startsWith("⏹")) { this.isExecuting = false; // 命令执行结束,允许用户继续输入 this.$nextTick(() => { this.$refs.commandInput.focus(); // 命令结束后重新聚焦到输入框 }); return; } this.currentOutput += output.trim() + '\n'; this.$nextTick(() => { if (this.$refs.outputPre) { this.$refs.outputPre.scrollTop = this.$refs.outputPre.scrollHeight; } }); }); this.stompClient.onDisconnect = () => { subscription.unsubscribe(); }; // 检查命令执行状态 await this.checkCommandStatus(); } catch (error) { console.error('WebSocket连接失败:', error); } }, async checkCommandStatus() { try { const response = await fetch(`/win/status/${this.userId}`); if (!response.ok) { console.error('无法获取命令状态'); return; } this.isExecuting = await response.json(); // 更新前端状态 if (this.isExecuting) { alert("上一个命令尚未完成,请等待或中止命令!"); } } catch (error) { console.error('检查命令状态时出错:', error); } }, sendCommand() { if (this.userId === '') { alert("请输入当前登录用户"); return; } this.isExecuting = true; if (this.currentCommand.trim() && this.stompClient) { // 删除 currentOutput 的最后一个非空行 if (this.currentOutput) { let lastNewLineIndex = this.currentOutput.lastIndexOf('\n'); let lastNonEmptyIndex = -1; // 从后往前遍历,找到最后一个非空行的起始位置 for (let i = this.currentOutput.length - 1; i >= 0; i--) { if (this.currentOutput[i] === '\n') { // 如果当前字符是换行符,并且之前的字符不是空白字符,则记录位置 if (lastNewLineIndex !== -1 && i < lastNewLineIndex) { lastNonEmptyIndex = lastNewLineIndex; break; } lastNewLineIndex = i; } else if (this.currentOutput[i].trim() !== '') { // 找到非空字符,更新 lastNewLineIndex lastNewLineIndex = i; } } // 如果找到了非空行,则删除它 if (lastNonEmptyIndex !== -1) { const nextNewLineIndex = this.currentOutput.indexOf('\n', lastNonEmptyIndex); if (nextNewLineIndex === -1) { this.currentOutput = this.currentOutput.substring(0, lastNonEmptyIndex); } else { this.currentOutput = this.currentOutput.substring(0, lastNonEmptyIndex) + this.currentOutput.substring(nextNewLineIndex); } } // 删除最后一个空行 if (this.currentOutput.endsWith('\n')) { this.currentOutput = this.currentOutput.substring(0, this.currentOutput.length - 1); } } // 发送命令 this.stompClient.publish({ destination: '/app/executeCommand', body: JSON.stringify({ command: this.currentCommand.trim(), //todo 之后改为动态 host: '10.228.73.15', userId: this.userId }), }); this.messages.push(this.index + '. ' + this.currentCommand); this.index += 1; this.currentCommand = ''; } }, async abortCommand() { if (this.stompClient) { const response = await fetch(`/win/handleAbort/${this.userId}`); if (response){ this.messages.push("已发送中止命令"); } } }, onTabChange(key, type) { this[type] = key; }, }, beforeDestroy() { if (this.stompClient) { this.stompClient.deactivate(); } } } </script> <style scoped> pre { white-space: pre-line; background-color: #f4f4f4; padding: 10px; border: 1px solid #ddd; } </style>为什么我这上面的可以连接成功,并发送成功。但是我本地访问ws://10.228.73.15:7788/websocket不成功。使用package com.example.demo.config; import org.springframework.messaging.converter.MappingJackson2MessageConverter; import org.springframework.messaging.simp.stomp.*; import org.springframework.util.MimeTypeUtils; import org.springframework.web.socket.WebSocketHttpHeaders; import org.springframework.web.socket.client.standard.StandardWebSocketClient; import org.springframework.web.socket.messaging.WebSocketStompClient; import java.util.HashMap; import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; public class StompClientSender { private final String serverUrl = "ws://10.228.73.15:7788/websocket"; // 根据实际端口调整 private WebSocketStompClient stompClient; public StompClientSender() { this.stompClient = new WebSocketStompClient(new StandardWebSocketClient()); stompClient.setMessageConverter(new MappingJackson2MessageConverter()); } public void sendCommand(String command, String host, String userId) { CompletableFuture<Void> future = new CompletableFuture<>(); try { StompSessionHandler sessionHandler = new StompSessionHandlerAdapter() { @Override public void afterConnected(StompSession session, StompHeaders connectedHeaders) { System.out.println("✅ 成功连接到STOMP服务器Session ID: " + session.getSessionId()); StompHeaders headers = new StompHeaders(); headers.setDestination("/app/executeCommand"); headers.setContentType(MimeTypeUtils.APPLICATION_JSON); Map<String, Object> payload = new HashMap<>(); payload.put("command", command); payload.put("host", host); payload.put("userId", userId); session.send(headers, payload); // 使用带headers的send方法 future.complete(null); session.disconnect(); } @Override public void handleException(StompSession session, StompCommand command, StompHeaders headers, byte[] payload, Throwable exception) { future.completeExceptionally(exception); } }; // 建立连接 stompClient.connect( serverUrl, new WebSocketHttpHeaders(), new StompHeaders(), sessionHandler ); future.get(5, TimeUnit.SECONDS); // 添加5秒超时等待 } catch (Exception e) { e.printStackTrace(); // 打印详细错误 future.completeExceptionally(e); } } }也不成功
最新发布
06-24
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值