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

查看:26
本文介绍了从 Web Socket @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().

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().

或者换一种说法...

  • 请求 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 对象确实存在于每个端点实例"中.

EndpointConfig objects do exist per "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

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

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() 调用访问 UserProperties,该调用始终可用.此用户属性映射始终可用,无论是通过注释技术(例如 @OnOpen@OnClose@OnError 期间的 Session 参数),或 @OnMessage 调用),通过会话的 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升级
  • 如果无效,则返回错误以升级响应
  • 创建握手响应
  • 在 HandshakeResponse 中存储答案
  • 在 HandshakeResponse 中存储答案

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

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

这是有意的,也是期望的,目的是让实现者拥有多种功能.

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

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

如果实现为每次握手都创建了一个新的配置器,那么这种技术将是不可能的.

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

(披露:我为 Jetty 9 编写和维护 JSR-356 实现)

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

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