从Web套接字@ServerEndpoint中的HttpServletRequest访问HttpSession [英] Accessing HttpSession from HttpServletRequest in a Web Socket @ServerEndpoint

查看:189
本文介绍了从Web套接字@ServerEndpoint中的HttpServletRequest访问HttpSession的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否可以在@ServerEndpoint中获取HttpServletRequest?首先,我试图获取它,以便可以访问HttpSession对象.

Is it possible to get the HttpServletRequest inside a @ServerEndpoint? Primarily I am trying to get it so I can access the HttpSession object.

推荐答案

更新(2016年11月):此答案中提供的信息适用于JSR356规范,该规范的各个实现可能会在此信息之外有所不同.在注释和其他答案中发现的其他建议,都是JSR356规范之外的特定于实现的行为.

Update (November 2016): The information provided in this answer is for the JSR356 spec, individual implementations of the spec may vary outside of this information. Other suggestions found in comments and other answers are all implementation specific behaviors outside of the JSR356 spec.

如果此处的建议引起您的问题,请升级Jetty,Tomcat,Wildfly或Glassfish/Tyrus的各种安装.据报告,这些实现的所有当前版本都可以按以下概述的方式工作.

If the suggestions in here are causing you problems, upgrade your various installations of Jetty, Tomcat, Wildfly, or Glassfish/Tyrus. All current versions of those implementations have all been reported to work in the way outlined below.

现在回到 2013年8月 ...

Now back to the original answer from August 2013...

马丁·安德森(Martin Andersson)的答案存在并发缺陷. Configurator可以同时被多个线程调用,在modifyHandshake()getEndpointInstance()的调用之间,您很可能无法访问正确的HttpSession对象.

The answer from Martin Andersson has a concurrency flaw. The Configurator can be called by multiple threads at the same time, it is likely that you will not have access to the correct HttpSession object between the calls from modifyHandshake() and getEndpointInstance().

或者说另一种方式...

Or said another way...

  • 请求A
  • 修改握手A
  • 请求B
  • 修改握手B
  • 获取端点实例A<-这将具有请求B的HttpSession
  • 获取端点实例B

这是对Martin代码的修改,该代码使用ServerEndpointConfig.getUserProperties()映射使HttpSession@OnOpen方法调用期间可用于您的套接字实例

Here's a modification to Martin's code that uses ServerEndpointConfig.getUserProperties() map to make the HttpSession available to your socket instance during the @OnOpen method call

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或强制转换.

Bonus feature: no instanceof or casting required.

一些EndpointConfig知识

EndpointConfig个对象.

但是,"Endpoint Instance"规范有2个含义.

However, an "Endpoint Instance" has 2 meanings with the spec.

  1. JSR的默认行为,其中每个传入的升级请求都会导致端点类的新对象实例
  2. javax.websocket.Session,将对象端点实例及其配置与特定的逻辑连接联系在一起.
  1. Default behavior of the JSR, where each incoming upgrade request results in a new object instance of the endpoint class
  2. A javax.websocket.Session that ties together the object endpoint instance, with its configuration, to a specific logical connection.

可能有一个单例Endpoint实例用于多个javax.websocket.Session实例(这是ServerEndpointConfig.Configurator支持的功能之一)

It is possible to have a singleton Endpoint instance being used for multiple javax.websocket.Session instances (that is one of the features that ServerEndpointConfig.Configurator supports)

ServerContainer实现将跟踪一组ServerEndpointConfig,它们代表服务器可以响应Websocket升级请求的所有已部署终结点.

The ServerContainer implementation will track a set of ServerEndpointConfig's that represent all of the deployed endpoints that the server can respond to a websocket upgrade request.

这些ServerEndpointConfig对象实例可以来自几个不同的来源.

These ServerEndpointConfig object instances can come from a few different sources.

  1. javax.websocket.server.ServerContainer.addEndpoint(ServerEndpointConfig)手动提供
    • 通常在javax.servlet.ServletContextInitializer.contextInitialized(ServletContextEvent sce)通话中完成
  1. Manually provided by the javax.websocket.server.ServerContainer.addEndpoint(ServerEndpointConfig)
    • Usually done within a javax.servlet.ServletContextInitializer.contextInitialized(ServletContextEvent sce) call

当最终创建javax.websocket.Session时,这些ServerEndpointConfig对象实例作为默认实例存在.

These ServerEndpointConfig object instances exist as defaults for when a javax.websocket.Session does eventually get created.

ServerEndpointConfig.Configurator实例

在接收或处理任何升级请求之前,所有ServerEndpointConfig.Configurator对象现在都已存在,并准备执行其主要和唯一目的,以允许自定义Websocket连接到最终javax.websocket.Session的升级过程.

Before any upgrade requests are received or processed, all of the ServerEndpointConfig.Configurator objects now exist and are ready to perform their main and sole purpose, to allow for customization of the upgrade process of a websocket connection to an eventual javax.websocket.Session

访问特定于会话的EndpointConfig

注意,您不能从端点实例内访问ServerEndpointConfig对象实例.您只能访问EndpointConfig实例.

Note, you cannot access the ServerEndpointConfig object instances from within a endpoint instance. You can only access EndpointConfig instances.

这意味着,如果您在部署过程中提供了ServerContainer.addEndpoint(new MyCustomServerEndpointConfig()),后来又尝试通过注释访问它,则它将不起作用.

This means if you provided ServerContainer.addEndpoint(new MyCustomServerEndpointConfig()) during deploy and later tried to access it via the annotations, it will not work.

以下所有内容均无效.

@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无法以任何其他方式或在任何其他时间使用.

You can access the EndpointConfig during the life of the Endpoint object instance, but under a limited time. The javax.websocket.Endpoint.onOpen(Session,Endpoint), annotated @OnOpen methods, or via the use of CDI. The EndpointConfig is not available in any other way or at any other time.

但是,您始终可以通过Session.getUserProperties()调用(始终可用)访问UserProperty.通过注释技术(例如,在@OnOpen@OnClose@OnError@OnMessage调用期间的Session参数),通过Session的CDI注入,甚至使用使用从javax.websocket.Endpoint扩展的非注释websocket.

However, you can always access the UserProperties via the Session.getUserProperties() call, which is available always. This User Properties map is always available, be it via the annotated techniques (such as a Session parameter during @OnOpen, @OnClose, @OnError, or @OnMessage calls), via CDI injection of the Session, or even with the use of non-annotated websockets that extend from javax.websocket.Endpoint.

升级方式

如前所述,每个定义的端点都将有一个ServerEndpointConfig与之关联.

As stated before, every one of the defined endpoints will have a ServerEndpointConfig associated with it.

这些ServerEndpointConfigs是单个实例,代表EndpointConfig的默认状态,这些默认状态最终可供可能并最终创建的端点实例使用.

Those ServerEndpointConfigs are a single instance that represents the default state of the EndpointConfig that are eventually made available to the Endpoint Instances that are possibly and eventually created.

当传入的升级请求到达时,它已在JSR上进行了以下操作.

When a incoming upgrade request arrives, it has go through the following on the JSR.

  1. 该路径是否匹配任何ServerEndpointConfig.getPath()条目
    • 如果没有匹配项,则返回404进行升级
  1. does the path match any of the ServerEndpointConfig.getPath() entries
    • If no match, return 404 to upgrade
  • 如果无效,请返回错误以升级响应
  • 创建HandshakeResponse
  • 将答案存储在HandshakeResponse中
  • 将答案存储在HandshakeResponse中

请注意,每个映射的ServerContainer端点的ServerEndpointConfig.Configurator是一个单例.

To note, the ServerEndpointConfig.Configurator is a singleton, per mapped ServerContainer endpoint.

这是故意的并且是希望的,以允许实现者一些功能.

This is intentional, and desired, to allow implementors several features.

  • 为多个对等节点返回同一个Endpoint实例(如果他们愿意).所谓的无状态Websocket编写方法.
  • 对所有Endpoint实例进行昂贵资源的单点管理

如果实现为每次握手创建一个新的Configurator,则此技术将无法实现.

If the implementations created a new Configurator for every handshake, this technique would not be possible.

(披露:我编写并维护了Jetty 9的JSR-356实现)

这篇关于从Web套接字@ServerEndpoint中的HttpServletRequest访问HttpSession的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆