请问有没有人尝试过使用嵌入式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());
}
}
}
}
}
}
}