【问题标题】:Why HandshakeRequest doesn't return HttpSession in my ServerEndpointConfig.Configurator?为什么 HandshakeRequest 不会在我的 ServerEndpointConfig.Configurator 中返回 HttpSession?
【发布时间】:2014-05-13 04:34:22
【问题描述】:

在 Websocket 和 Rest 服务之间共享 HttpSession 有一个很好的例子。 (Spring DispatchServlet cannot find resource within Jetty) 但这对我不起作用。我不确定我是否缺少任何东西?

我使用 Jetty 作为 websocket 服务器,还创建了一个由 SpringConfig 注入的 WebApp。

private void init() throws Exception
{
    Server server = new Server();

    // Create SSL Connector
    ServerConnector serverConnector = getSSLConnector(server);

    // Bundle to server
    server.setConnectors(new Connector[] { serverConnector });

    // Create request handler collection
    HandlerCollection handlers = new HandlerCollection();


    // Add WebSocket handler
    final ServletContextHandler servletContextHandler = getWebSocketContextHandler();
    handlers.addHandler(servletContextHandler);

    // Add Servlet handler
    handlers.addHandler(getWebAppServletContextHandler());


    server.setHandler(handlers);
    // Initial WebSocket
    WebSocketServerContainerInitializer.configureContext(servletContextHandler);

    // Start Jetty
    server.start();
    server.join();
}

WebSocket 和 Rest 都在同一个端口下完美地工作,当然,使用不同的上下文路径。

现在,我创建了一个 Rest 服务:

@RequestMapping(value = "/login", method = RequestMethod.POST)
@Consumes({ MediaType.APPLICATION_JSON_VALUE })
@Produces({ MediaType.APPLICATION_JSON_VALUE })
public @ResponseBody Message login(@RequestBody Credential credential, @Context HttpServletRequest servlerRequest) 
{
    ...
    HttpSession session = servlerRequest.getSession(true);
    session.setAttribute("userName", credential.getUserName());
    ...
    Message message = new Message();
    ...
    return message;
}

在此服务中,我创建了一个 HttpSession 并在其中存储了一些内容。正如我所说,它有效,会话也有效。

休息客户端:

public void login() throws KeyManagementException, NoSuchAlgorithmException
{
    final String loginServiceUri = HTTP_SERVICE_BASE_URI + "/login";

    ClientConfig clientConfig = new DefaultClientConfig();
    ...

    Client client = Client.create(clientConfig);
    WebResource webResource = client.resource(loginServiceUri);
    ClientResponse response = webResource
            .type("application/json")
            .post(ClientResponse.class, new Credential("user","pass"));

    if (response.getStatus() != 200) {
        throw new RuntimeException("Failed : HTTP error code : " + response.getStatus());
    }

    List<NewCookie>cookies = response.getCookies();
    ClientEndpointConfigurator.setCookies(cookies);     <== Store cookies as well as session to ClientEndpointConfigrator class

    Message message = response.getEntity(Message.class);
    ...
}

ClientEndpointConfigrator 类有一个所有 cookie 的静态列表,如下所示:

public class ClientEndpointConfigurator extends ClientEndpointConfig.Configurator {
    private static List<NewCookie> cookies = null;
    public static void setCookies(List<NewCookie> cookies) {
        ClientEndpointConfigurator.cookies = cookies;
    }
    ...
    @Override
    public void beforeRequest(Map<String, List<String>> headers) {
        ...
        if(null != cookies)
        {
            List<String> cookieList = new ArrayList<String>();
            for(NewCookie cookie: cookies)
            {
                cookieList.add(cookie.toString());
            }
            headers.put("Cookie", cookieList);
        }
        ...
    }
}

beforeRequest() 方法会将所有 cookie 放入请求标头。如果您检查 cookieList,您将看到:

[JSESSIONID=tvum36z6j2bc1p9uf2gumxguh;Version=1;Path=/rs;Secure]

事情看起来很完美。

最后,创建一个服务端ServerEndpointConfigurator类,重写modifyHandshake()方法来获取session和cookie

public class SpringServerEndpointConfigurator extends ServerEndpointConfig.Configurator {
    @Override
    public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
        super.modifyHandshake(sec, request, response);
        httpSession = (HttpSession)request.getHttpSession();    <== **It returns null here!**
        ...

        }
    }
}

我无法找回我的 HttpSession!如果您打印出标题,您将看到 cookie 已更改:

Cookie:JSESSIONID="tvum36z6j2bc1p9uf2gumxguh";$Path="/rs"

有人知道是什么原因吗?

【问题讨论】:

    标签: rest session websocket share endpoint


    【解决方案1】:

    好吧,我想通了,这是因为我将 WebSocket 和 Rest 放到了不同的上下文处理程序中。 Jetty 使处理程序彼此隔离。要共享会话信息,您必须将它们放在一起。

    但是如果有人确实想将它们分开,仍然可以通过共享 SessionManager 或 SessionHandler 来完成。有很多方法可以实现这一点,您可以将 SessionHandler 注入每个 ServletContext 或将其定义为静态变量并将其放在每个人都可以到达的地方,每种方式都有效。

    【讨论】:

      猜你喜欢
      • 2015-12-28
      • 2022-06-14
      • 2012-11-08
      • 2013-02-19
      • 1970-01-01
      • 2012-12-30
      • 1970-01-01
      • 2012-05-11
      • 2015-02-04
      相关资源
      最近更新 更多