Я разрабатываю приложение веб-сервиса Java (с JAX-WS), который должен использовать два различных прокси для установления разделенных соединений с Интернетом и интранет. Как решение я пытался записать свой собственный java.net. ProxySelector, который возвращает java.net. Экземпляр прокси (типа HTTP) для Интернета или интранет.
В небольшом тестовом приложении я пытаюсь загрузить веб-страницу через URL.openConnection (), и прежде чем я заменил ProxySelector по умолчанию своим собственным. Но это приводит к исключению:
java.net. SocketException: Неизвестный тип прокси: HTTP в java.net. SocksSocketImpl.connect(SocksSocketImpl.java:370) в java.net. Socket.connect (Сокет java:519) в java.net. Socket.connect (Сокет java:469) в sun.net. NetworkClient.doConnect(NetworkClient.java:163) в sun.net.www.http. HttpClient.openServer(HttpClient.java:394) в sun.net.www.http. HttpClient.openServer(HttpClient.java:529) в sun.net.www.http. HttpClient. (HttpClient.java:233) в sun.net.www.http. HttpClient. Новый (HttpClient.java:306) в sun.net.www.protocol.http. HttpURLConnection.getNewHttpClient(HttpURLConnection.java:844) в sun.net.www.protocol.http. HttpURLConnection.plainConnect(HttpURLConnection.java:792) в sun.net.www.protocol.http. HttpURLConnection.connect(HttpURLConnection.java:703) в sun.net.www.protocol.http. HttpURLConnection.getInputStream(HttpURLConnection.java:1026) в java.net. HttpURLConnection.getResponseCode(HttpURLConnection.java:373) в norman.test. ProxyTest.conntectToRmViaProxy(ProxyTest.java:42) в norman.test. ProxyTest.main(ProxyTest.java:65)
2 Вопроса: "Есть ли альтернатива, для определения различных прокси для каждого соединения?"
Это - мой ProxySelector:
public class OwnProxySelector extends ProxySelector {
private Proxy intranetProxy;
private Proxy extranetProxy;
private Proxy directConnection = Proxy.NO_PROXY;
private URI intranetAddress;
private URI extranetAddress;
/* (non-Javadoc)
* @see java.net.ProxySelector#connectFailed(java.net.URI, java.net.SocketAddress, java.io.IOException)
*/
public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
// Nothing to do
}
/* (non-Javadoc)
* @see java.net.ProxySelector#select(java.net.URI)
*/
public List select(URI uri) {
ArrayList<Proxy> result = new ArrayList<Proxy>();
if(intranetAddress.getHost().equals(uri.getHost()) && intranetAddress.getPort()==uri.getPort()){
result.add(intranetProxy);
System.out.println("Adding intranet Proxy!");
}
else if(extranetAddress.getHost().equals(uri.getHost()) && extranetAddress.getPort()==uri.getPort()){
result.add(extranetProxy);
System.out.println("Adding extranet Proxy!");
}
else{
result.add(directConnection);
System.out.println("Adding direct connection!");
}
return result;
}
public void setIntranetProxy(String proxyAddress, int proxyPort){
if(proxyAddress==null || proxyAddress.isEmpty()){
intranetProxy = Proxy.NO_PROXY;
}
else{
SocketAddress address = new InetSocketAddress(proxyAddress, proxyPort);
intranetProxy = new Proxy(Proxy.Type.HTTP, address);
}
}
public void setExtranetProxy(String proxyAddress, int proxyPort){
if(proxyAddress==null || proxyAddress.isEmpty()){
extranetProxy = Proxy.NO_PROXY;
}
else{
SocketAddress address = new InetSocketAddress(proxyAddress, proxyPort);
extranetProxy = new Proxy(Proxy.Type.HTTP, address);
}
}
public void clearIntranetProxy(){
intranetProxy = Proxy.NO_PROXY;
}
public void clearExtranetProxy(){
extranetProxy = Proxy.NO_PROXY;
}
public void setIntranetAddress(String address) throws URISyntaxException{
intranetAddress = new URI(address);
}
public void setExtranetAddress(String address) throws URISyntaxException{
extranetAddress = new URI(address);
}
}
Это - тестовый класс:
public class ProxyTest {
OwnProxySelector ownSelector = new OwnProxySelector();
public ProxyTest(){
ownSelector.setIntranetProxy("intranet.proxy", 8123);
try {
ownSelector.setIntranetAddress("http://intranet:80");
} catch (URISyntaxException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
ownSelector.setExtranetProxy("", 0);
try {
ownSelector.setExtranetAddress("http://www.example.com:80");
} catch (URISyntaxException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
ProxySelector.setDefault(ownSelector);
}
public void conntectToRmViaProxy(boolean internal, String connectAddress){
try {
URL url = new URL(connectAddress);
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setRequestMethod("GET");
if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) {
System.out.println(conn.getResponseMessage());
}
else{
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
int tmp = reader.read();
while(tmp != -1){
System.out.print((char)tmp);
tmp = reader.read();
}
}
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args){
ProxyTest proxyText = new ProxyTest();
proxyText.conntectToRmViaProxy(true, "http://intranet:80");
}
}
Хорошо, я нашел проблему.
HttpURLConnection выполняет OwnProxySelector.select() дважды, если запрашиваемый URL не содержит порт.
Сначала HttpURLConnection вызвал select() с URI, имеющим схему "http", но без порта. Функция select() проверяет, соответствуют ли адрес хоста и порт адресу intranetAddress или extranetAddress. Этого не произошло, так как порт не был указан. Поэтому select возвращает Proxy для прямого соединения.
При втором HttpURLConnection был вызван select() с URI, со схемой "socket" и портом 80. Так как select() проверяет адрес хоста и порт, но не схему, он вернул HTTP-прокси.
Теперь вот моя исправленная версия OwnProxySelector. Он проверяет схему и устанавливает порт по умолчанию для HTTP или HTTPS, если порт не указан в URI. Также он запрашивает стандартный Java ProxySelector, если не указана схема HTTP или HTTPS.
public class OwnProxySelector extends ProxySelector {
private ProxySelector defaultProxySelector;
private Proxy intranetProxy;
private Proxy extranetProxy;
private Proxy directConnection = Proxy.NO_PROXY;
private URI intranetAddress;
private URI extranetAddress;
public OwnProxySelector(ProxySelector defaultProxySelector){
this.defaultProxySelector = defaultProxySelector;
}
/* (non-Javadoc)
* @see java.net.ProxySelector#connectFailed(java.net.URI, java.net.SocketAddress, java.io.IOException)
*/
public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
// Nothing to do
}
/* (non-Javadoc)
* @see java.net.ProxySelector#select(java.net.URI)
*/
public List select(URI uri) {
ArrayList<Proxy> result = new ArrayList<Proxy>();
if(uri.getScheme().equalsIgnoreCase("http") || uri.getScheme().equalsIgnoreCase("https")){
int uriPort = uri.getPort();
// set default http and https ports if port is not given in URI
if(uriPort<1){
if(uri.getScheme().equalsIgnoreCase("http")){
uriPort = 80;
}
else if(uri.getScheme().equalsIgnoreCase("http")){
uriPort = 443;
}
}
if(intranetAddress.getHost().equals(uri.getHost()) && intranetAddress.getPort()==uriPort){
result.add(intranetProxy);
System.out.println("Adding intranet Proxy!");
}
else if(extranetAddress.getHost().equals(uri.getHost()) && extranetAddress.getPort()==uriPort){
result.add(extranetProxy);
System.out.println("Adding extranet Proxy!");
}
}
if(result.isEmpty()){
List<Proxy> defaultResult = defaultProxySelector.select(uri);
if(defaultResult!=null && !defaultResult.isEmpty()){
result.addAll(defaultResult);
System.out.println("Adding Proxis from default selector.");
}
else{
result.add(directConnection);
System.out.println("Adding direct connection, because requested URI does not match any Proxy");
}
}
return result;
}
public void setIntranetProxy(String proxyAddress, int proxyPort){
if(proxyAddress==null || proxyAddress.isEmpty()){
intranetProxy = Proxy.NO_PROXY;
}
else{
SocketAddress address = new InetSocketAddress(proxyAddress, proxyPort);
intranetProxy = new Proxy(Proxy.Type.HTTP, address);
}
}
public void setExtranetProxy(String proxyAddress, int proxyPort){
if(proxyAddress==null || proxyAddress.isEmpty()){
extranetProxy = Proxy.NO_PROXY;
}
else{
SocketAddress address = new InetSocketAddress(proxyAddress, proxyPort);
extranetProxy = new Proxy(Proxy.Type.HTTP, address);
}
}
public void clearIntranetProxy(){
intranetProxy = Proxy.NO_PROXY;
}
public void clearExtranetProxy(){
extranetProxy = Proxy.NO_PROXY;
}
public void setIntranetAddress(String address) throws URISyntaxException{
intranetAddress = new URI(address);
}
public void setExtranetAddress(String address) throws URISyntaxException{
extranetAddress = new URI(address);
}
}
Но мне любопытно, что HttpURLConnection сделал второй вызов select(), когда он получил прямое соединение Proxy от первого вызова.