Jetty WebSocket代理

时间:2014-03-07 23:08:00

标签: proxy websocket jetty

只是想知道是否有人使用嵌入式Jetty试验过WebSocket代理(透明代理)?

用Jetty 9.1.2.v20140210玩了大约一天半之后,我所知道的是它无法以当前形式代理WebSockets,并且添加这样的支持是非常重要的任务(至少是afaict)

基本上,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 个答案:

答案 0 :(得分:1)

让我们假设您正在尝试构建的代理方案,我们有客户 A ,服务器 B 和代理 P 。现在让我们来看看连接工作流程: 1. A 与代理 P (A-P)建立的TCP连接 2. A 使用WebSocket握手发送 CONNECT addr(B)请求

这里有第一个问题,WS握手中使用的HTTP RFC标头不是端到端标头,因为对于HTTP,它们仅在传输层(两个跃点之间)有意义。

  1. P 建立与 B的连接(P-B)
  2. P 将WS握手HTTP请求发送到 B
  3. B 以HTTP-> WS升级响应(通过发送101)
  4. 这是另一个问题,在发送HTTP 101服务器 B 之后,客户端 A 现在只能通过TCP进行通信,但是jetty servlet不支持普通的TCP数据包传播。换句话说,jetty代理servlet会等到客户端 A 开始传输HTTP请求,这在 A 接收HTTP 101后永远不会发生。

    您需要使用WS服务器和WS客户端自行实现。