1. Introduction
1.介绍
Proxy servers act as intermediaries between client applications and other servers. In an enterprise setting, we often use them to help provide control over the content that users consume, usually across network boundaries.
代理服务器作为客户应用和其他服务器之间的中间人。在企业环境中,我们经常使用它们来帮助控制用户消费的内容,通常是跨越网络边界。
In this tutorial, we’ll look at how to connect through proxy servers in Java.
在本教程中,我们将探讨如何在Java中通过代理服务器进行连接。
First, we’ll explore the older, more global approach that is JVM-wide and configured with system properties. Afterward, we’ll introduce the Proxy class, which gives us more control by allowing configuration on a per-connection basis.
首先,我们将探讨旧的、更全局的方法,即在JVM范围内并通过系统属性进行配置。之后,我们将介绍Proxy类,该类允许在每个连接的基础上进行配置,从而为我们提供更多的控制。
2. Setup
2.设置
To run the samples in this article, we’ll need access to a proxy server. Squid is a popular implementation that is available for most operating systems. The default configuration of Squid will be good enough for most of our examples.
为了运行本文中的样本,我们需要访问一个代理服务器。Squid是一个流行的实现,可用于大多数操作系统。Squid的默认配置对于我们的大多数例子来说已经足够好了。
3. Using a Global Setting
3.使用全局设置
Java exposes a set of system properties that can be used to configure JVM-wide behavior. This “one size fits all approach” is often the simplest to implement if it’s appropriate for the use case.
Java公开了一组系统属性,可用于配置JVM范围内的行为。这种 “一刀切 “的方法,如果适合用例,往往是最简单的实现。
We can set the required properties from the command line when invoking the JVM. As an alternative, we can also set them by calling System.setProperty() at runtime.
我们可以在调用JVM时从命令行中设置所需的属性。作为一种选择,我们也可以通过在运行时调用System.setProperty()来设置它们。
3.1. Available System Properties
3.1.可用的系统属性
Java provides proxy handlers for HTTP, HTTPS, FTP, and SOCKS protocols. A proxy can be defined for each handler as a hostname and port number:
Java为HTTP、HTTPS、FTP和SOCKS协议提供代理处理程序。每个处理程序的代理可以被定义为一个主机名和端口号。
- http.proxyHost – The hostname of the HTTP proxy server
- http.proxyPort – The port number of the HTTP proxy server – property is optional and defaults to 80 if not provided
- http.nonProxyHosts – A pipe-delimited (“|”) list of host patterns for which the proxy should be bypassed – applies for both the HTTP and HTTPS handlers if set
- socksProxyHost – The hostname of the SOCKS proxy server
- socksProxyPort – The port number of the SOCKS proxy server
If specifying nonProxyHosts, host patterns may start or end with a wildcard character (“*”). It may be necessary to escape the “|” delimiter on Windows platforms. An exhaustive list of all available proxy-related system properties can be found in Oracle’s official Java documentation on networking properties.
如果指定nonProxyHosts,主机模式可以以通配符(”*”)开始或结束。在Windows平台上可能需要转义”|”分界符。在Oracle关于网络属性的官方Java文档中,可以找到所有可用的代理相关系统属性的详尽列表。
3.2. Set via Command Line Arguments
3.2.通过命令行参数设置
We can define proxies on the command line by passing in the settings as system properties:
我们可以在命令行上定义代理,将设置作为系统属性传入。
java -Dhttp.proxyHost=127.0.0.1 -Dhttp.proxyPort=3128 com.baeldung.networking.proxies.CommandLineProxyDemo
When starting a process in this way, we’re able to simply use openConnection() on the URL without any additional work:
当以这种方式启动一个进程时,我们能够简单地在URL上使用openConnection(),而无需任何额外的工作。
URL url = new URL(RESOURCE_URL);
URLConnection con = url.openConnection();
3.3. Set Using System.setProperty(String, String)
3.3.使用System.setProperty(String, String)进行设置
If we’re unable to set proxy properties on the command line, we can set them with calls to System.setProperty() within our program:
如果我们无法在命令行上设置代理属性,我们可以在程序中通过调用System.setProperty()来设置它们。
System.setProperty("http.proxyHost", "127.0.0.1");
System.setProperty("http.proxyPort", "3128");
URL url = new URL(RESOURCE_URL);
URLConnection con = url.openConnection();
// ...
If we later unset the relevant system properties manually, then the proxy will no longer be used:
如果我们后来手动取消了相关的系统属性,那么代理将不再被使用。
System.setProperty("http.proxyHost", null);
3.4. Limitations of Global Configuration
3.4.全局配置的局限性
Although using a global configuration with system properties is easy to implement, this approach limits what we can do because the settings apply across the entire JVM. For this reason, settings defined for a particular protocol are active for the life of the JVM or until they are un-set.
虽然使用系统属性的全局配置很容易实现,但这种方法限制了我们能做的事情,因为这些设置适用于整个JVM。出于这个原因,为某一特定协议定义的设置在JVM的生命周期中是有效的,或者直到它们被取消设置。
To get around this limitation, it might be tempting to flip the settings on and off as needed. To do this safely in a multi-threaded program, it would be necessary to introduce measures to protect against concurrency issues.
为了绕过这个限制,我们可能很想根据需要打开或关闭这些设置。为了在多线程程序中安全地做到这一点,有必要引入措施来防止并发问题。
As an alternative, the Proxy API provides more granular control over proxy configuration.
作为一种选择,代理API提供了对代理配置的更精细的控制。
4. Using the Proxy API
4.使用ProxyAPI
The Proxy class gives us a flexible way to configure proxies on a per-connection basis. If there are any existing JVM-wide proxy settings, connection-based proxy settings using the Proxy class will override them.
Proxy类为我们提供了一种灵活的方式来配置基于每个连接的代理。如果有任何现有的JVM范围的代理设置,使用Proxy类的基于连接的代理设置将覆盖它们。
There are three types of proxies that we can define by Proxy.Type:
有三种类型的代理,我们可以通过Proxy.Type定义。
- HTTP – a proxy using the HTTP protocol
- SOCKS – a proxy using the SOCKS protocol
- DIRECT – an explicitly configured direct connection without a proxy
4.1. Using an HTTP Proxy
4.1.使用一个HTTP代理
To use an HTTP proxy, we first wrap a SocketAddress instance with a Proxy and type of Proxy.Type.HTTP. Next, we simply pass the Proxy instance to URLConnection.openConnection():
要使用HTTP代理,我们首先用Proxy和Proxy.Type.HTTP的类型包裹一个SocketAddress实例。接下来,我们简单地将这个Proxy实例传递给URLConnection.openConnection():
URL weburl = new URL(URL_STRING);
Proxy webProxy
= new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 3128));
HttpURLConnection webProxyConnection
= (HttpURLConnection) weburl.openConnection(webProxy);
Simply put, this means that we’ll connect to URL_STRING, but then route that connection through a proxy server hosted at 127.0.0.1:3128.
简单地说,这意味着我们将连接到URL_STRING,但然后通过托管在127.0.0.1:3128的代理服务器路由该连接。
4.2. Using a DIRECT Proxy
4.2.使用DIRECT代理
We may have a requirement to connect directly to a host. In this case, we can explicitly bypass a proxy that may be configured globally by using the static Proxy.NO_PROXY instance. Under the covers, the API constructs a new instance of Proxy for us, using Proxy.Type.DIRECT as the type:
我们可能有直接连接到一个主机的要求。在这种情况下,我们可以通过使用静态的Proxy.NO_PROXY实例明确地绕过可能被全局配置的代理。掩盖之下,API为我们构造了一个新的Proxy实例,使用Proxy.Type.DIRECT作为类型:。
HttpURLConnection directConnection
= (HttpURLConnection) weburl.openConnection(Proxy.NO_PROXY);
Basically, if there is no globally configured proxy, then this is the same as calling openConnection() with no arguments.
基本上,如果没有全局配置的代理,那么这与调用openConnection()没有参数的情况下相同。
4.3. Using a SOCKS Proxy
4.3.使用SOCKS代理
Using a SOCKS proxy is similar to the HTTP variant when working with URLConnection. We start by wrapping a SocketAddress instance with a Proxy using a type of Proxy.Type.SOCKS. Afterward, we pass the Proxy instance to URLConnection.openConnection:
在使用URLConnection时,使用SOCKS代理与HTTP变体类似。我们首先用Proxy包裹一个SocketAddress实例,使用Proxy.Type.SOCKS的类型。之后,我们将这个Proxy实例传递给URLConnection.openConnection。
Proxy socksProxy
= new Proxy(Proxy.Type.SOCKS, new InetSocketAddress("127.0.0.1", 1080));
HttpURLConnection socksConnection
= (HttpURLConnection) weburl.openConnection(socksProxy);
It’s also possible to use a SOCKS proxy when connecting to a TCP socket. First, we use the Proxy instance to construct a Socket. Afterward, we pass the destination SocketAddress instance to Socket.connect():
在连接到TCP套接字时也可以使用SOCKS代理。首先,我们使用Proxy实例来构造一个Socket。之后,我们将目标SocketAddress实例传递给Socket.connect()。
Socket proxySocket = new Socket(socksProxy);
InetSocketAddress socketHost
= new InetSocketAddress(SOCKET_SERVER_HOST, SOCKET_SERVER_PORT);
proxySocket.connect(socketHost);
5. Conclusion
5.结论
In this article, we looked at how to work with proxy servers in core Java.
在这篇文章中,我们研究了如何在核心Java中使用代理服务器。
First, we looked at the older, more global style of connecting through proxy servers using system properties. Then, we saw how to use the Proxy class, which provides fine-grained control when connecting through proxy servers.
首先,我们看了使用系统属性通过代理服务器连接的旧的、更全局的方式。然后,我们看到了如何使用Proxy类,它在通过代理服务器连接时提供了精细的控制。
As always, all source code used in this article can be found over on GitHub.
一如既往,本文中使用的所有源代码都可以在GitHub上找到。