(これはJava 8とTomcat 8です)Tomcat WebソケットがJVM全体のHTTPプロキシ設定を尊重しないのはなぜですか?
私はsquidプロキシに対してテストしようとしている単純なwebsocketクライアントテストアプリケーションを持っています。私はhttp[s].proxy[Host|Port]
システムプロパティを使用して、JVM全体のレベルでプロキシ情報を設定しています。私はツロの実装(tyrus-standalone-client-1.12.jar
)の特性を光栄にプロキシシステムを使用する場合
(もちろん、私はwss
URLは動作しないという問題があるが、それは別の問題です)。
しかし、Tomcatの実装(tomcat-websocket.jar
)を使用すると、システムプロキシの設定は経験的に無視されます(ネットワークスニファを使用していますが、パケットはプロキシには流れませんが、Tyrusではパケットが表示されますプロキシへ)。
org.apache.tomcat.websocket.WsWebSocketContainer.connectToServer()
にソースを見て、それは確かにそれは、プロキシ情報をピックアップし、それを使用しているように見える:私は私のテストプログラムにプロキシを見上げているコードの一部を入れ
// Check to see if a proxy is configured. Javadoc indicates return value
// will never be null
List<Proxy> proxies = ProxySelector.getDefault().select(proxyPath);
Proxy selectedProxy = null;
for (Proxy proxy : proxies) {
if (proxy.type().equals(Proxy.Type.HTTP)) {
sa = proxy.address();
if (sa instanceof InetSocketAddress) {
InetSocketAddress inet = (InetSocketAddress) sa;
if (inet.isUnresolved()) {
sa = new InetSocketAddress(inet.getHostName(), inet.getPort());
}
}
selectedProxy = proxy;
break;
}
}
それが何を発見していたかを見るために、プロキシ情報を取得します。だから私はなぜTomcatのWebソケットがプロパティを尊重しているのか分からない。
私のテストのアプリ:
import javax.websocket.*;
import java.net.Proxy;
import java.net.ProxySelector;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;
/**
* This class is adapted from http://stackoverflow.com/a/26454417/411393 which
* is an answer to http://stackoverflow.com/questions/26452903/javax-websocket-client-simple-example/
*/
public class WebsocketTestApp
{
public static void main(String[] args) {
try {
// Determine where to connect
final URI servicePath;
if ((args.length != 0) && "secure".equals(args[0])) {
// servicePath = new URI("wss://real.okcoin.cn:10440/websocket/okcoinapi");
servicePath = new URI("wss://echo.websocket.org/");
}
else {
servicePath = new URI("ws://echo.websocket.org/");
}
// See what Java thinks the proxy for the service is.
URI proxyPath = buildProxyPath(servicePath);
System.out.println("service path: " + servicePath);
System.out.println("proxy path: " + proxyPath);
// This line is copied from the source to org.apache.tomcat.websocket.WsWebSocketContainer (approx line 254)
List<Proxy> proxies = ProxySelector.getDefault().select(proxyPath);
for (Proxy proxy : proxies) {
System.out.println(proxy.toString());
}
// open websocket
final WebsocketClientEndpoint clientEndPoint = new WebsocketClientEndpoint(servicePath);
// add listener
clientEndPoint.addMessageHandler(System.out::println);
// send message to websocket
clientEndPoint.sendMessage("{'event':'addChannel','channel':'ok_btccny_ticker'}");
// wait 2 seconds for messages from websocket
Thread.sleep(2000);
}
catch (InterruptedException ex) {
System.err.println("InterruptedException exception: " + ex.getMessage());
}
catch (URISyntaxException ex) {
System.err.println("URISyntaxException exception: " + ex.getMessage());
}
}
// This is essentially copied from the source to org.apache.tomcat.websocket.WsWebSocketContainer (approx lines 230-241)
private static URI buildProxyPath(URI path) {
URI proxyPath;
// Validate scheme (and build proxyPath)
String scheme = path.getScheme();
if ("ws".equalsIgnoreCase(scheme)) {
proxyPath = URI.create("http" + path.toString().substring(2));
}
else if ("wss".equalsIgnoreCase(scheme)) {
proxyPath = URI.create("https" + path.toString().substring(3));
}
else {
throw new IllegalArgumentException("wsWebSocketContainer.pathWrongScheme: " + scheme);
}
return proxyPath;
}
@ClientEndpoint
public static class WebsocketClientEndpoint
{
Session userSession = null;
private MessageHandler messageHandler;
public WebsocketClientEndpoint(URI endpointURI) {
try {
WebSocketContainer container = ContainerProvider.getWebSocketContainer();
//((ClientManager)container).getProperties().put(ClientProperties.PROXY_URI, "http://172.16.99.15:3128");
container.connectToServer(this, endpointURI);
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* Callback hook for Connection open events.
*
* @param userSession the userSession which is opened.
*/
@OnOpen
public void onOpen(Session userSession) {
System.out.println("opening websocket");
this.userSession = userSession;
}
/**
* Callback hook for Connection close events.
*
* @param userSession the userSession which is getting closed.
* @param reason the reason for connection close
*/
@OnClose
public void onClose(Session userSession, CloseReason reason) {
System.out.println("closing websocket");
this.userSession = null;
}
/**
* Callback hook for Message Events. This method will be invoked when a client send a message.
*
* @param message The text message
*/
@OnMessage
public void onMessage(String message) {
if (this.messageHandler != null) {
this.messageHandler.handleMessage(message);
}
}
/**
* register message handler
*
* @param msgHandler
*/
public void addMessageHandler(MessageHandler msgHandler) {
this.messageHandler = msgHandler;
}
/**
* Send a message.
*
* @param message
*/
public void sendMessage(String message) {
this.userSession.getAsyncRemote().sendText(message);
}
/**
* Message handler.
*/
@FunctionalInterface
public static interface MessageHandler
{
public void handleMessage(String message);
}
}
}
そして、私はそれを実行すると、出力は次のようになります。
service path: ws://echo.websocket.org/
proxy path: http://echo.websocket.org/
HTTP @ 172.16.99.15:3128
opening websocket
{'event':'addChannel','channel':'ok_btccny_ticker'}
だから、WsWebSocketContainer.connectToServer()
が使用しているのと同じルックアップコードを使用して、正しいプロキシ情報をプリントアウトされますプロキシ情報は受け付けられず、代わりに直接接続されています。
Tomcatの実装ではこれが奇妙なバグですか? Tomcatの実装はプロキシのプロパティ設定を無視することが知られていますか?
UPDATE:
私はまた、実行中のTomcatでの迅速な&汚いサーブレットにコードを入れて、同じことが起こります。 Tomcat全体が設定を尊重しているようですが(Tomcatのjava.net.URL.openStream()
を呼び出すと設定が優先されます)、websocketの設定は再び設定を尊重することを拒否します。これを引き起こしているのはではなく、のコードはTomcatのコンテナではなくスタンドアロンで実行されています。