Nhiều lần, một ứng dụng Java cần kết nối với Internet. Ví dụ phổ biến nhất xảy ra khi nó đang đọc một tệp XML và cần tải xuống lược đồ của nó.
Tôi đứng sau một máy chủ proxy. Làm cách nào tôi có thể thiết lập JVM của mình để sử dụng proxy?
Nhiều lần, một ứng dụng Java cần kết nối với Internet. Ví dụ phổ biến nhất xảy ra khi nó đang đọc một tệp XML và cần tải xuống lược đồ của nó.
Tôi đứng sau một máy chủ proxy. Làm cách nào tôi có thể thiết lập JVM của mình để sử dụng proxy?
Câu trả lời:
Từ tài liệu Java ( không phải API javadoc):
http://doad.oracle.com/javase/6/docs/technotes/guides/net/proxies.html
Đặt các cờ JVM http.proxyHost
và http.proxyPort
khi bắt đầu JVM của bạn trên dòng lệnh. Điều này thường được thực hiện trong một tập lệnh shell (trong Unix) hoặc tập tin bat (trong Windows). Đây là ví dụ với tập lệnh shell Unix:
JAVA_FLAGS=-Dhttp.proxyHost=10.0.0.100 -Dhttp.proxyPort=8800
java ${JAVA_FLAGS} ...
Khi sử dụng các thùng chứa như JBoss hoặc WebLogic, giải pháp của tôi là chỉnh sửa các tập lệnh khởi động được cung cấp bởi nhà cung cấp.
Nhiều nhà phát triển đã quen thuộc với API Java (javadocs), nhưng nhiều lần phần còn lại của tài liệu bị bỏ qua. Nó chứa rất nhiều thông tin thú vị: http://doad.oracle.com/javase/6/docs/technotes/guides/
Cập nhật: Nếu bạn không muốn sử dụng proxy để giải quyết một số máy chủ lưu trữ cục bộ / mạng nội bộ, hãy xem nhận xét từ @Tomalak:
Cũng đừng quên thuộc tính http.nonProxyhosts!
-Dhttp.nonProxyHosts="localhost|127.0.0.1|10.*.*.*|*.foo.com|etc"
http.nonProxyHosts
tài sản! (sử dụng như thế này -Dhttp.nonProxyHosts="localhost|127.0.0.1|10.*.*.*|*.foo.com|etc"
:)
http.proxyUser
và http.proxyPassword
không phải là thuộc tính hệ thống Java. Chúng dành cho máy khách HTTP Apache.
https.proxyHost
và https.proxyPort
cho HTTP.
Để sử dụng thiết lập proxy hệ thống:
java -Djava.net.useSystemProxies=true ...
Hoặc theo chương trình:
System.setProperty("java.net.useSystemProxies", "true");
Nguồn: http://docs.oracle.com/javase/7/docs/api/java/net/doc-files/net-properIES.html
Để đặt proxy HTTP / HTTPS và / hoặc SOCKS theo chương trình:
...
public void setProxy() {
if (isUseHTTPProxy()) {
// HTTP/HTTPS Proxy
System.setProperty("http.proxyHost", getHTTPHost());
System.setProperty("http.proxyPort", getHTTPPort());
System.setProperty("https.proxyHost", getHTTPHost());
System.setProperty("https.proxyPort", getHTTPPort());
if (isUseHTTPAuth()) {
String encoded = new String(Base64.encodeBase64((getHTTPUsername() + ":" + getHTTPPassword()).getBytes()));
con.setRequestProperty("Proxy-Authorization", "Basic " + encoded);
Authenticator.setDefault(new ProxyAuth(getHTTPUsername(), getHTTPPassword()));
}
}
if (isUseSOCKSProxy()) {
// SOCKS Proxy
System.setProperty("socksProxyHost", getSOCKSHost());
System.setProperty("socksProxyPort", getSOCKSPort());
if (isUseSOCKSAuth()) {
System.setProperty("java.net.socks.username", getSOCKSUsername());
System.setProperty("java.net.socks.password", getSOCKSPassword());
Authenticator.setDefault(new ProxyAuth(getSOCKSUsername(), getSOCKSPassword()));
}
}
}
...
public class ProxyAuth extends Authenticator {
private PasswordAuthentication auth;
private ProxyAuth(String user, String password) {
auth = new PasswordAuthentication(user, password == null ? new char[]{} : password.toCharArray());
}
protected PasswordAuthentication getPasswordAuthentication() {
return auth;
}
}
...
Hãy nhớ rằng proxy HTTP và proxy SOCKS hoạt động ở các cấp khác nhau trong ngăn xếp mạng, vì vậy bạn có thể sử dụng một hoặc một hoặc cả hai.
Bạn có thể đặt các cờ đó theo cách lập trình theo cách này:
if (needsProxy()) {
System.setProperty("http.proxyHost",getProxyHost());
System.setProperty("http.proxyPort",getProxyPort());
} else {
System.setProperty("http.proxyHost","");
System.setProperty("http.proxyPort","");
}
Chỉ cần trả lại giá trị ngay từ những phương pháp needsProxy()
, getProxyHost()
và getProxyPort()
và bạn có thể gọi đoạn mã này bất cứ khi nào bạn muốn.
JVM sử dụng proxy để thực hiện các cuộc gọi HTTP
System.getProperties().put("http.proxyHost", "someProxyURL");
System.getProperties().put("http.proxyPort", "someProxyPort");
Điều này có thể sử dụng proxy cài đặt người dùng
System.setProperty("java.net.useSystemProxies", "true");
System.setProperty
thay vìSystem.getProperties().put(...)
Bạn có thể đặt một số thuộc tính về máy chủ proxy làm tham số jvm
-Dhttp.proxyPort = 8080, proxyhost, v.v.
nhưng nếu bạn cần thông qua một proxy xác thực, bạn cần một trình xác thực như ví dụ này:
ProxyAuthenticator.java
import java.net.*;
import java.io.*;
public class ProxyAuthenticator extends Authenticator {
private String userName, password;
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(userName, password.toCharArray());
}
public ProxyAuthenticator(String userName, String password) {
this.userName = userName;
this.password = password;
}
}
Ví dụ
import java.net.Authenticator;
import ProxyAuthenticator;
public class Example {
public static void main(String[] args) {
String username = System.getProperty("proxy.authentication.username");
String password = System.getProperty("proxy.authentication.password");
if (username != null && !username.equals("")) {
Authenticator.setDefault(new ProxyAuthenticator(username, password));
}
// here your JVM will be authenticated
}
}
Dựa trên câu trả lời này: http://mail-archives.apache.org/mod_mbox/jakarta-jmeter-user/200208.mbox/%3C494FD350388AD511A9DD00025530F33102F1DC2C@MMSX006%3E
Đặt thuộc java.net.useSystemProxies
tính thành true
. Bạn có thể đặt nó, ví dụ, thông qua biến môi trường JAVA_TOOL_OPTIONS . Trong Ubuntu, bạn có thể, ví dụ, thêm dòng sau vào .bashrc
:
xuất JAVA_TOOL_OPTIONS + = "-Djava.net.useSystemProxies = true"
Phần sau đây cho thấy cách đặt trong Java một proxy bằng mật khẩu người dùng và mật khẩu proxy từ dòng lệnh, đây là trường hợp rất phổ biến. Bạn không nên lưu mật khẩu và máy chủ lưu trữ trong mã, như một quy tắc ở nơi đầu tiên.
Truyền các thuộc tính hệ thống trong dòng lệnh với -D và đặt chúng trong mã với System.setProperty ("name", "value") là tương đương.
Nhưng lưu ý điều này
Ví dụ hoạt động:
C:\temp>java -Dhttps.proxyHost=host -Dhttps.proxyPort=port -Dhttps.proxyUser=user -Dhttps.proxyPassword="password" -Djavax.net.ssl.trustStore=c:/cacerts -Djavax.net.ssl.trustStorePassword=changeit com.andreas.JavaNetHttpConnection
Nhưng những điều sau đây không hoạt động :
C:\temp>java com.andreas.JavaNetHttpConnection -Dhttps.proxyHost=host -Dhttps.proxyPort=port -Dhttps=proxyUser=user -Dhttps.proxyPassword="password" -Djavax.net.ssl.trustStore=c:/cacerts -Djavax.net.ssl.trustStorePassword=changeit
Sự khác biệt duy nhất là vị trí của các thuộc tính hệ thống! (trước và sau giờ học)
Nếu bạn có các ký tự đặc biệt trong mật khẩu, bạn được phép đặt nó trong dấu ngoặc kép "@ MyPass123%", như trong ví dụ trên.
Nếu bạn truy cập dịch vụ HTTPS, bạn phải sử dụng https.proxyHost
, https.proxyPort
v.v.
Nếu bạn truy cập dịch vụ HTTP, bạn phải sử dụng http.proxyHost
, http.proxyPort
v.v.
đọc một tệp XML và cần tải xuống lược đồ của nó
Nếu bạn đang tính đến việc truy xuất các lược đồ hoặc DTD qua internet, bạn đang xây dựng một ứng dụng chậm, trò chuyện, dễ vỡ. Điều gì xảy ra khi máy chủ từ xa lưu trữ tệp mất thời gian dự kiến hoặc không có kế hoạch? Ứng dụng của bạn bị hỏng. Ổn chứ?
Xem http://xml.apache.org/commons/components/resolver/resolver-article.html#s.catalog.files
URL cho các lược đồ và tương tự được coi là định danh duy nhất. Không phải là yêu cầu để thực sự truy cập tập tin đó từ xa. Thực hiện một số tìm kiếm google trên "Danh mục XML". Một danh mục XML cho phép bạn lưu trữ các tài nguyên đó cục bộ, giải quyết sự chậm chạp, chậm chạp và mong manh.
Về cơ bản, nó là một bản sao lưu vĩnh viễn của nội dung từ xa. Và không sao, vì nội dung từ xa sẽ không bao giờ thay đổi. Nếu có một bản cập nhật, nó sẽ ở một URL khác. Làm cho việc lấy tài nguyên thực tế qua internet đặc biệt là ngớ ngẩn.
Tôi cũng đứng sau tường lửa, điều này làm việc cho tôi !!
System.setProperty("http.proxyHost", "proxy host addr");
System.setProperty("http.proxyPort", "808");
Authenticator.setDefault(new Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("domain\\user","password".toCharArray());
}
});
URL url = new URL("http://www.google.com/");
URLConnection con = url.openConnection();
BufferedReader in = new BufferedReader(new InputStreamReader(
con.getInputStream()));
// Read it ...
String inputLine;
while ((inputLine = in.readLine()) != null)
System.out.println(inputLine);
in.close();
Nếu bạn muốn "Vớ Proxy", hãy thông báo cho các đối số VM "vớProxyhost" và "vớProxyPort".
ví dụ
java -DsocksProxyHost=127.0.0.1 -DsocksProxyPort=8080 org.example.Main
Thêm phần này trước khi bạn kết nối với một URL phía sau proxy.
System.getProperties().put("http.proxyHost", "someProxyURL");
System.getProperties().put("http.proxyPort", "someProxyPort");
System.getProperties().put("http.proxyUser", "someUserName");
System.getProperties().put("http.proxyPassword", "somePassword");
http.proxyUser
và http.proxyPassword
không phải là thuộc tính hệ thống Java. Chúng dành cho máy khách HTTP Apache.
System.setProperty
thay vìSystem.getProperties().put(...)
Đây là một bản cập nhật nhỏ, nhưng kể từ Java 7, các kết nối proxy giờ đây có thể được tạo bằng lập trình thay vì thông qua các thuộc tính hệ thống. Điều này có thể hữu ích nếu:
Đây là một ví dụ giả định trong Groovy:
// proxy configuration read from file resource under "proxyFileName"
String proxyFileName = "proxy.txt"
String proxyPort = "1234"
String url = "http://www.promised.land"
File testProxyFile = new File(proxyFileName)
URLConnection connection
if (!testProxyFile.exists()) {
logger.debug "proxyFileName doesn't exist. Bypassing connection via proxy."
connection = url.toURL().openConnection()
} else {
String proxyAddress = testProxyFile.text
connection = url.toURL().openConnection(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyAddress, proxyPort)))
}
try {
connection.connect()
}
catch (Exception e) {
logger.error e.printStackTrace()
}
Tham khảo đầy đủ: http://docs.oracle.com/javase/7/docs/technotes/guides/net/proxies.html
Gần đây tôi đã phát hiện ra cách cho phép JVM sử dụng cài đặt proxy trình duyệt. Những gì bạn cần làm là thêm ${java.home}/lib/deploy.jar
vào dự án của bạn và khởi tạo thư viện như sau:
import com.sun.deploy.net.proxy.DeployProxySelector;
import com.sun.deploy.services.PlatformType;
import com.sun.deploy.services.ServiceManager;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public abstract class ExtendedProxyManager {
private static final Log logger = LogFactory.getLog(ExtendedProxyManager.class);
/**
* After calling this method, proxy settings can be magically retrieved from default browser settings.
*/
public static boolean init() {
logger.debug("Init started");
// Initialization code was taken from com.sun.deploy.ClientContainer:
ServiceManager
.setService(System.getProperty("os.name").toLowerCase().indexOf("windows") != -1 ? PlatformType.STANDALONE_TIGER_WIN32
: PlatformType.STANDALONE_TIGER_UNIX);
try {
// This will call ProxySelector.setDefault():
DeployProxySelector.reset();
} catch (Throwable throwable) {
logger.error("Unable to initialize extended dynamic browser proxy settings support.", throwable);
return false;
}
return true;
}
}
Sau đó, các cài đặt proxy có sẵn cho API Java thông qua java.net.ProxySelector
.
Vấn đề duy nhất với cách tiếp cận này là bạn cần khởi động JVM với deploy.jar
trong bootgrouppath, vd java -Xbootclasspath/a:"%JAVA_HOME%\jre\lib\deploy.jar" -jar my.jar
. Nếu ai đó biết cách vượt qua giới hạn này, hãy cho tôi biết.
xbootclasspath
trỏ đến triển khai.jar sẽ có tác dụng gì, tôi không thể đưa cái bình đó lên đường dẫn lớp thông thường của tôi (khi chạy mà không có webstart)?
Exception in thread "main" java.lang.IllegalAccessError: class ...) cannot access class com.sun.deploy.net.proxy.DeployProxySelector (in module jdk.deploy) because module jdk.deploy does not export com.sun.deploy.net.proxy
Nó ổn với tôi:
public void setHttpProxy(boolean isNeedProxy) {
if (isNeedProxy) {
System.setProperty("http.proxyHost", getProxyHost());
System.setProperty("http.proxyPort", getProxyPort());
} else {
System.clearProperty("http.proxyHost");
System.clearProperty("http.proxyPort");
}
}
P / S: Tôi dựa trên câu trả lời của GHad.
Như được chỉ ra trong các câu trả lời khác, nếu bạn cần sử dụng proxy xác thực, không có cách nào đáng tin cậy để thực hiện việc này hoàn toàn bằng cách sử dụng các biến dòng lệnh - gây phiền nhiễu nếu bạn đang sử dụng ứng dụng của người khác và không muốn gây rối với mã nguồn.
Iverson sẽ đưa ra gợi ý hữu ích tại Sử dụng HttpProxy để kết nối với máy chủ có xác thực định trước để sử dụng công cụ quản lý Proxy như Proxifier ( http://www.proxifier.com/ cho Mac OS X và Windows) để xử lý việc này.
Ví dụ với Proxifier, bạn có thể thiết lập nó để chỉ chặn các lệnh java được quản lý và chuyển hướng thông qua proxy (xác thực) của nó. Tuy nhiên, bạn sẽ muốn đặt các giá trị proxyhost và proxyPort trong trường hợp này, ví dụ: truyền vào -Dhttp.proxyHost= -Dhttp.proxyPort=
các lệnh java của bạn.
Bạn có thể sử dụng các biến JVM http.proxy * nếu bạn ở trong một JVM độc lập nhưng bạn KHÔNG NÊN sửa đổi các tập lệnh khởi động của chúng và / hoặc thực hiện điều này trong máy chủ ứng dụng của bạn (ngoại trừ có thể là jboss hoặc tomcat). Thay vào đó, bạn nên sử dụng API Proxy JAVA (không phải System.setProperty) hoặc sử dụng các tùy chọn cấu hình của nhà cung cấp. Cả WebSphere và WebLogic đều có những cách rất rõ ràng để thiết lập các proxy mạnh hơn nhiều so với J2SE. Ngoài ra, đối với WebSphere và WebLogic, bạn có thể sẽ phá vỡ máy chủ ứng dụng của mình bằng cách ghi đè các tập lệnh khởi động (đặc biệt là các quy trình xen kẽ của máy chủ như bạn có thể bảo chúng sử dụng proxy của mình ...).
Tôi nghĩ rằng cấu hình WINHTTP cũng sẽ hoạt động.
Nhiều chương trình bao gồm Windows Updates đang gặp vấn đề đằng sau proxy. Bằng cách thiết lập WINHTTP sẽ luôn khắc phục loại sự cố này