为什么HandshakeRequest在我的ServerEndpointConfig.Configurator中没有返回HttpSession?



有一个在Websocket和Rest服务之间共享HttpSession的好例子。(Spring DispatchServlet无法在Jetty中找到资源)但它不适合我。我不确定我是不是漏掉了什么?

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

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并存储了一些东西。如我所说,它有效,会话也有效。

Rest客户端:

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;路径=/rs;安全)

一切都很顺利。

最后,创建服务器端ServerEndpointConfigurator类,并重写modifyHandshake()方法以检索会话和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已经被改变了:

饼干:JSESSIONID ="tvum36z6j2bc1p9uf2gumxguh";$路径= "/rs "

有谁知道原因是什么吗?

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

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

相关内容

  • 没有找到相关文章

最新更新