从Web Socket @ServerEndpoint中的HttpServletRequest

是否可以在@ServerEndpoint中获取HttpServletRequest?主要是我试图得到它所以我可以访问HttpSession对象。



饮歌长啸
浏览 4552回答 3
3回答

慕村9548890

Configurator可以同时由多个线程调用,很可能您无法在来自modifyHandshake()和的调用之间访问正确的HttpSession对象getEndpointInstance()。或者说另一种方式......请求A.修改握手A.请求B.修改握手B.获取端点实例A < - 这将具有请求B的HttpSession获取端点实例B.这是对Martin的代码的修改,它使用ServerEndpointConfig.getUserProperties()map HttpSession在@OnOpen方法调用期间使套接字实例可用GetHttpSessionConfigurator.javapackage 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.javapackage 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将对象端点实例及其配置连接到特定逻辑连接的A。可以将单个端点实例用于多个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())在部署期间提供并稍后尝试通过注释访问它,则它将无法工作。以下所有内容均无效。@OnOpenpublic void onOpen(Session session, EndpointConfig config){    MyCustomServerEndpointConfig myconfig = (MyCustomServerEndpointConfig) config;    /* this would fail as the config is cannot be cast around like that */}// --- or ---@OnOpenpublic void onOpen(Session session, ServerEndpointConfig config){    /* For @OnOpen, the websocket implementation would assume       that the ServerEndpointConfig to be a declared PathParam     */}// --- or ---@OnOpenpublic 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()呼叫访问UserProperties,该呼叫始终可用。此用户属性地图总是可用的,通过注释的技术(如在会话期间的参数是它@OnOpen,@OnClose,@OnError,或@OnMessage呼叫),通过CDI注射会话的,或者即使使用,从延长非注释的WebSockets的javax.websocket.Endpoint。升级如何运作如前所述,每个定义的端点都将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)上使用class创建Session,关联端点实例和EndpointConfig对象。通知连接的端点实例需要EndpointConfig的带注释的方法获取与此Session关联的方法。调用Session.getUserProperties()返回EndpointConfig.getUserProperties()需要注意的是,ServerEndpointConfig.Configurator是每个映射的ServerContainer端点的单例。这是有意的,并且是期望的,以允许实现者具有若干特征。如果他们愿意,为多个对等体返回相同的Endpoint实例。所谓无状态的websocket写作方法。为所有Endpoint实例提供昂贵资源的单点管理如果实现为每次握手创建了新的Configurator,则该技术将无法实现。

天涯尽头无女友

可能吗?让我们回顾一下Java API for WebSocket规范,看看是否可以获取HttpSession对象。该规范说,第29页:因为websocket连接是使用http请求启动的,所以在客户端运行的HttpSession和在该HttpSession中建立的任何websockets之间存在关联。API允许在打开握手中访问对应于同一客户端的唯一HttpSession。所以是的,这是可能的。但是,我认为你不可能获得HttpServletRequest对象的引用。您可以使用a 监听所有新的servlet请求ServletRequestListener,但您仍然需要确定哪个请求属于哪个服务器端点。如果您找到解决方案,请告诉我们!抽象的方法如何在说明书的第13页和第14页中对其进行了松散的描述,并在下一个标题下以代码示例。在英语中,我们需要拦截握手过程以获取HttpSession对象。然后,为了将HttpSession引用传递给我们的服务器端点,我们还需要在容器创建服务器端点实例并手动注入引用时进行拦截。我们通过提供我们自己ServerEndpointConfig.Configurator的方法modifyHandshake()并覆盖方法来完成所有这些getEndpointInstance()。自定义配置程序将按逻辑实例化一次ServerEndpoint(请参阅JavaDoc)。代码示例这是服务器端点类(我在此代码片段之后提供了CustomConfigurator类的实现):@ServerEndpoint(value = "/myserverendpoint", configurator = CustomConfigurator.class)public class MyServerEndpoint{&nbsp; &nbsp; private HttpSession httpSession;&nbsp; &nbsp; public void setHttpSession(HttpSession httpSession) {&nbsp; &nbsp; &nbsp; &nbsp; if (this.httpSession != null) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throw new IllegalStateException("HttpSession has already been set!");&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; this.httpSession = httpSession;&nbsp; &nbsp; }&nbsp; &nbsp; @OnOpen&nbsp; &nbsp; public void onOpen(Session session, EndpointConfig config) {&nbsp; &nbsp; &nbsp; &nbsp; System.out.println("My Session Id: " + httpSession.getId());&nbsp; &nbsp; }}这是自定义配置器:public class CustomConfigurator extends ServerEndpointConfig.Configurator{&nbsp; &nbsp; private HttpSession httpSession;&nbsp; &nbsp; // modifyHandshake() is called before getEndpointInstance()!&nbsp; &nbsp; @Override&nbsp; &nbsp; public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {&nbsp; &nbsp; &nbsp; &nbsp; httpSession = (HttpSession) request.getHttpSession();&nbsp; &nbsp; &nbsp; &nbsp; super.modifyHandshake(sec, request, response);&nbsp; &nbsp; }&nbsp; &nbsp; @Override&nbsp; &nbsp; public <T> T getEndpointInstance(Class<T> endpointClass) throws InstantiationException {&nbsp; &nbsp; &nbsp; &nbsp; T endpoint = super.getEndpointInstance(endpointClass);&nbsp; &nbsp; &nbsp; &nbsp; if (endpoint instanceof MyServerEndpoint) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // The injection point:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ((MyServerEndpoint) endpoint).setHttpSession(httpSession);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; else {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throw new InstantiationException(&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MessageFormat.format("Expected instanceof \"{0}\". Got instanceof \"{1}\".",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MyServerEndpoint.class, endpoint.getClass()));&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return endpoint;&nbsp; &nbsp; }}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java