是否可以在@ServerEndpoint中获取HttpServletRequest?首先,我正在尝试获取它,以便可以访问HttpSession对象。
最佳答案
更新(2016年11月):此答案中提供的信息适用于JSR356规范,该规范的各个实现可能会在此信息之外有所不同。注释和其他答案中提供的其他建议都是JSR356规范之外的特定于实现的行为。
如果此处的建议引起您问题,请升级Jetty,Tomcat,Wildfly或Glassfish / Tyrus的各种安装。据报告,这些实现的所有当前版本都以下面概述的方式工作。
现在回到2013年8月的原始答案...
Martin Andersson的答案存在并发缺陷。 Configurator可以同时由多个线程调用,在modifyHandshake()
和getEndpointInstance()
的调用之间,您很可能无法访问正确的HttpSession对象。
或说另一种方式...
请求A
修改握手A
要求B
修改握手B
获取端点实例A 获取端点实例B
这是对Martin代码的修改,该代码使用ServerEndpointConfig.getUserProperties()
映射使HttpSession
在@OnOpen
方法调用期间可用于套接字实例。
GetHttpSessionConfigurator.java
package examples;
import javax.servlet.http.HttpSession;
import javax.websocket.HandshakeResponse;
import javax.websocket.server.HandshakeRequest;
import javax.websocket.server.ServerEndpointConfig;
public class GetHttpSessionConfigurator extends ServerEndpointConfig.Configurator
{
@Override
public void modifyHandshake(ServerEndpointConfig config,
HandshakeRequest request,
HandshakeResponse response)
{
HttpSession httpSession = (HttpSession)request.getHttpSession();
config.getUserProperties().put(HttpSession.class.getName(),httpSession);
}
}
GetHttpSessionSocket.java
package examples;
import java.io.IOException;
import javax.servlet.http.HttpSession;
import javax.websocket.EndpointConfig;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
@ServerEndpoint(value = "/example",
configurator = GetHttpSessionConfigurator.class)
public class GetHttpSessionSocket
{
private Session wsSession;
private HttpSession httpSession;
@OnOpen
public void open(Session session, EndpointConfig config) {
this.wsSession = session;
this.httpSession = (HttpSession) config.getUserProperties()
.get(HttpSession.class.getName());
}
@OnMessage
public void echo(String msg) throws IOException {
wsSession.getBasicRemote().sendText(msg);
}
}
额外功能:无需
instanceof
或强制转换。一些EndpointConfig知识
每个“端点实例”确实存在
EndpointConfig
个对象。但是,“端点实例”在规范中有2个含义。
JSR的默认行为,其中每个传入的升级请求都会导致端点类的新对象实例
一个
javax.websocket.Session
将对象端点实例及其配置与特定的逻辑连接联系在一起。可能有一个Singleton Endpoint实例用于多个
javax.websocket.Session
实例(这是ServerEndpointConfig.Configurator
支持的功能之一)ServerContainer实现将跟踪一组ServerEndpointConfig,它们代表服务器可以响应Websocket升级请求的所有已部署终结点。
这些ServerEndpointConfig对象实例可以来自几个不同的来源。
javax.websocket.server.ServerContainer.addEndpoint(ServerEndpointConfig)
手动提供通常在
javax.servlet.ServletContextInitializer.contextInitialized(ServletContextEvent sce)
调用中完成从
javax.websocket.server.ServerApplicationConfig.getEndpointConfigs(Set)
调用。通过扫描Web应用程序以查找
@ServerEndpoint
带注释的类自动创建。这些
ServerEndpointConfig
对象实例作为最终创建javax.websocket.Session
时的默认值存在。ServerEndpointConfig.Configurator实例
现在,在接收或处理任何升级请求之前,所有
ServerEndpointConfig.Configurator
对象均已存在,并准备执行其主要和唯一目的,以允许自定义Websocket连接到最终javax.websocket.Session
的升级过程。访问特定于会话的EndpointConfig
注意,您不能从端点实例内访问
ServerEndpointConfig
对象实例。您只能访问EndpointConfig
实例。这意味着,如果您在部署期间提供了
ServerContainer.addEndpoint(new MyCustomServerEndpointConfig())
,但后来又尝试通过注释访问它,则它将不起作用。以下所有内容均无效。
@OnOpen
public void onOpen(Session session, EndpointConfig config)
{
MyCustomServerEndpointConfig myconfig = (MyCustomServerEndpointConfig) config;
/* this would fail as the config is cannot be cast around like that */
}
// --- or ---
@OnOpen
public void onOpen(Session session, ServerEndpointConfig config)
{
/* For @OnOpen, the websocket implementation would assume
that the ServerEndpointConfig to be a declared PathParam
*/
}
// --- or ---
@OnOpen
public void onOpen(Session session, MyCustomServerEndpointConfig config)
{
/* Again, for @OnOpen, the websocket implementation would assume
that the MyCustomServerEndpointConfig to be a declared PathParam
*/
}
您可以在Endpoint对象实例的生存期内但在有限的时间内访问EndpointConfig。
javax.websocket.Endpoint.onOpen(Session,Endpoint)
,带注释的@OnOpen
方法或通过使用CDI。 EndpointConfig无法以任何其他方式或在任何其他时间使用。但是,您始终可以通过
Session.getUserProperties()
调用(始终可用)访问UserProperty。通过注释技术(例如,在@OnOpen
,@OnClose
,@OnError
或@OnMessage
调用期间的Session参数),通过Session的CDI注入,甚至通过使用从javax.websocket.Endpoint
扩展的非注释websocket。升级的工作方式
如前所述,每个定义的端点都会有一个
ServerEndpointConfig
与其关联。这些
ServerEndpointConfigs
是单个实例,表示EndpointConfig
的默认状态,这些默认状态最终可供可能并最终创建的端点实例使用。当传入的升级请求到达时,它已在JSR上进行了以下操作。
路径是否匹配任何ServerEndpointConfig.getPath()条目
如果不匹配,则返回404进行升级
将升级请求传递到ServerEndpointConfig.Configurator.checkOrigin()
如果无效,则返回错误以升级响应
创建HandshakeResponse
将升级请求传递到ServerEndpointConfig.Configurator.getNegotiatedSubprotocol()
将答案存储在HandshakeResponse中
将升级请求传递到ServerEndpointConfig.Configurator.getNegotiatedExtensions()
将答案存储在HandshakeResponse中
创建新的终结点特定的ServerEndpointConfig对象。复制编码器,解码器和用户属性。这个新的ServerEndpointConfig包装了路径,扩展名,端点类,子协议,配置器的默认值。
将升级请求,响应和新的ServerEndpointConfig传递到ServerEndpointConfig.Configurator.modifyHandshake()
调用ServerEndpointConfig.getEndpointClass()
在ServerEndpointConfig.Configurator.getEndpointInstance(Class)上使用类
创建会话,关联端点实例和EndpointConfig对象。
通知连接的端点实例
需要EndpointConfig的带注释的方法获取与此会话相关联的方法。
调用Session.getUserProperties()返回EndpointConfig.getUserProperties()
注意,ServerEndpointConfig.Configurator是每个映射的ServerContainer端点的一个单例。
这是有意实现的,它允许实现者具有多个功能。
如果多个对等方愿意,则返回相同的Endpoint实例。 Websocket编写的所谓无状态方法。
对所有Endpoint实例进行昂贵资源的单点管理
如果实现为每次握手创建一个新的Configurator,则此技术将无法实现。
(公开:我编写并维护了Jetty 9的JSR-356实现)
关于websocket - 从Web套接字@ServerEndpoint中的HttpServletRequest访问HttpSession,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/28000112/