Jetty WebSocket代理

24

请问有没有人尝试过使用嵌入式Jetty进行WebSocket代理(透明代理)的实验?

经过一天半的Jetty 9.1.2.v20140210实验,我所能说的就是它无法在当前形式下代理WebSockets,并且添加这样的支持是一项不容易的任务(至少在我的看法中是这样的)。
基本上,Jetty ProxyServlet会剥离“Upgrade”和“Connection”头字段,而不管它是否来自WebSocket握手请求。像下面展示的那样将这些字段添加回去很容易。但是,当被代理的服务器返回具有HTTP代码101(切换协议)的响应时,在代理服务器上不会进行协议升级。因此,当第一个WebSocket数据包到达时,HttpParser会出错,认为它是一个错误的HTTP请求。

如果有人已经针对此问题有解决方案或熟悉Jetty并建议尝试什么,那将非常感激。

以下是我实验中剥离了不重要部分的代码:

    public class ProxyServer
    {
        public static void main(String[] args) throws Exception
        {
            Server server = new Server();
            ServerConnector connector = new ServerConnector(server);
            connector.setPort(8888);
            server.addConnector(connector);

            // Setup proxy handler to handle CONNECT methods
            ConnectHandler proxy = new ConnectHandler();
            server.setHandler(proxy);

            // Setup proxy servlet
            ServletContextHandler context = new ServletContextHandler(proxy, "/", ServletContextHandler.SESSIONS);
            ServletHolder proxyServlet = new ServletHolder(MyProxyServlet.class);
            context.addServlet(proxyServlet, "/*");

            server.start();
        }
    }

    @SuppressWarnings("serial")
    public class MyProxyServlet extends ProxyServlet
    {
        @Override
        protected void customizeProxyRequest(Request proxyRequest, HttpServletRequest request)
        {
            // Pass through the upgrade and connection header fields for websocket handshake request. 
            String upgradeValue = request.getHeader("Upgrade");
            if (upgradeValue != null && upgradeValue.compareToIgnoreCase("websocket") == 0)
            {
                setHeader(proxyRequest, "Upgrade", upgradeValue);
                setHeader(proxyRequest, "Connection", request.getHeader("Connection"));
            }
        }

        @Override
        protected void onResponseHeaders(HttpServletRequest request, HttpServletResponse response, Response proxyResponse)
        {
            super.onResponseHeaders(request, response, proxyResponse);

            // Restore the upgrade and connection header fields for websocket handshake request.
            HttpFields fields = proxyResponse.getHeaders();
            for (HttpField field : fields)
            {
                if (field.getName().compareToIgnoreCase("Upgrade") == 0)
                {
                    String upgradeValue = field.getValue();
                    if (upgradeValue != null && upgradeValue.compareToIgnoreCase("websocket") == 0)
                    {
                        response.setHeader(field.getName(), upgradeValue);
                        for (HttpField searchField : fields)
                        {
                            if (searchField.getName().compareToIgnoreCase("Connection") == 0) {
                                response.setHeader(searchField.getName(), searchField.getValue());
                            }
                        }
                    }
                }
            }
        }
    }
1个回答

1
让我们想象一下你正在构建的代理方案,我们有客户端A,服务器B和代理P。现在让我们走一遍连接工作流程:
  1. A与代理P(A-P)建立TCP连接
  2. A发送带有WebSocket握手的CONNECT addr(B)请求
这里有第一个问题,根据HTTP RFC,用于WS握手的标头不是端到端标头,因为对于HTTP,它们只在传输层(两个跳之间)才有意义。
  1. PB(P-B)建立TCP连接
  2. PB发送WS握手HTTP请求
  3. B通过发送101响应HTTP->WS升级

这里还有另一个问题,在发送HTTP 101服务器B和客户端A之后,现在只能通过TCP进行通信,但是jetty servlet不支持纯TCP数据包传播。换句话说,jetty代理servlet会等待客户端A开始传输HTTP请求,但在A收到HTTP 101后永远不会发生。

您需要自己使用WS服务器和WS客户端实现此功能。


我已经尝试过使用嵌入式Tomcat,它可以正常工作。我在我的项目中使用了它。 - FranXho

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接