Java HTTP Proxy Server

2025年5月3日 | 阅读 7 分钟

在当今的企业开发环境中,我们通常需要与系统管理员打交道。在大多数情况下,应用程序将配置为使用系统的默认设置,但如果您想对应用程序进行非常严格的控制,例如代理设置,那么在这种情况下,Java 提供了 API。

代理服务器就像客户端应用程序和其他服务器之间的中间系统。在企业应用程序中,它用于在网络边界之间提供对用户内容的控制。下图演示了代理服务器的行为

Java HTTP Proxy Server

在本主题中,我们将了解如何在 Java 中通过代理服务器进行连接。我们将采用两种方法来创建与 Java 中代理服务器的连接。

  • 第一种方法是一种较旧的方法,它是 JVM 范围的,并通过系统属性进行配置。它被许多开发人员广泛使用。
  • 第二种方法是使用 Proxy 类,它通过允许基于每次连接进行配置来提供更多控制。

Proxy API 自 Java 5.0 起可用。但是,旧方法仍然有效,可以与我们的项目一起使用。但 Proxy 类的方法更有效且可定制。

使用代理服务器的优点

在以下情况下,代理服务器很有用

  • 捕获客户端和服务器之间的流量。
  • 控制和限制上传/下载带宽,以了解网站在慢速连接下的加载情况。
  • 分析系统在网络出现问题时的反应。
  • 更新客户端/服务器的内容。
  • 创建流量统计信息。

系统属性

Java 支持各种协议的代理处理程序,如FTP、HTTP、HTTPSSOCKS。我们可以为主机名和端口号定义的每个处理程序单独定义一个代理。以下系统属性可用于 Java 代理配置

  • proxyHost:定义 HTTP 代理服务器的主机名。
  • proxyPort:定义 HTTP 代理服务器的端口号。
  • 端口属性是一个可选属性,如果未提供,则默认为 80。
  • nonProxyHosts:定义一个用管道符("|")分隔的可用主机模式,我们希望绕过代理。此设置可应用于 HTTP 和 HTTPS 处理程序。
  • SocksProxyHost:定义 SOCKS 代理服务器的主机名。
  • SocksProxyPort:定义 SOCKS 代理服务器的端口号。

注意:我们可以使用通配符("*")来开始或结束 nonProxyHosts 中的主机模式。但在 Windows 平台上,必须删除 "|" 分隔符。所有可用的代理系统属性列表可以在这里找到。

使用全局设置

Java 提供了我们上面讨论过的几个系统属性来配置 JVM 范围的行为。这些属性易于针对特定用例实现。

我们也可以在使用 JVM 时通过命令行设置必要的属性。有一种替代方法可以做到这一点,那就是在运行时调用System.setProperty()方法。

让我们了解如何使用命令行设置它们

通过命令行设置代理

我们也可以使用命令行参数设置代理属性。要通过命令行定义代理,请按如下方式将设置作为系统属性传递

通过以这种方式启动进程,我们可以使用 URL 上的openConnection() 方法,而无需进行任何进一步的操作,如下所示

使用 System.setProperty() 方法设置代理

如果我们在使用命令行时遇到困难,有一种替代方法可以通过使用 System.setProperty() 方法来做到这一点。要使用此方法设置代理,请在程序中按如下方式定义它

之后,我们可以取消设置系统属性,如果需要,它们将从我们的应用程序中删除。要取消设置系统属性,请在程序中按如下方式将其定义为 null

全局设置存在一些限制,这时 Proxy API 就派上用场了。让我们讨论全局设置的局限性

全局配置方法的局限性

全局配置方法是定义代理最简单的方法,但这种方法存在一些局限性。

这种方法在 JVM 范围内提供实现,因此为特定协议设置的设置将在JVM 的生命周期内有效,或者直到我们手动取消设置它们。

为了克服这个限制,如果需要,开启和关闭设置可能会很有吸引力。但是,有必要确保采取措施来防止多线程程序中的并发问题。

因此,作为替代方案,Proxy API 更有效,并提供对代理配置的更多控制。

使用 Proxy API 设置代理

Java Proxy 类提供了一种便捷的方法,可以根据连接配置代理。如果我们使用 Proxy 类设置代理,它将覆盖现有的 JVM 范围代理设置。

使用 Proxy 类的 Proxy.Type() 方法可以定义三种类型的代理

  1. HTTP 代理(使用 HTTP 协议)
  2. SOCKS 代理(使用 SOCKS 协议)
  3. DIRECT 代理(这是一个显式配置的直接连接,无需代理)。

让我们来理解这些代理

1) HTTP 代理

要使用 HTTP 代理,请将 SocketAddress 实例与代理包装,并将类型提供为Proxy.Type.HTTP。现在,我们可以简单地将代理实例传递给URLConnection.openConnection(). 考虑下面的代码

现在,我们将连接到 URL_STRING,然后将该连接路由到托管在 127.0.0.1:3020 的代理服务器。

2) DIRECT 代理

Direct Proxy 对于直接连接到主机很有用。在这种情况下,我们必须通过使用静态 "proxy.NO_PROXY" 实例显式绕过可能已全局配置的代理。内部,Proxy API 会使用 Proxy.Type.Direct 类型创建一个新的代理实例。

请看下面的代码

基本上,如果没有全局配置的代理,那么这将与调用 openConnection() 而不带参数的效果相同。

3) SOCKS 代理

SOCKS 代理在处理 URLConnection 时与 HTTP 变体的工作方式类似。在 SOCKS 代理中,我们首先使用 Proxy.Type.SOCKS 类型将 SocketAddress 实例与 Proxy 包装。之后,将代理实例传递给 URLConnection.openConnection。考虑下面的代码

我们也可以在使用 SOCKS 代理连接到 TCP 套接字时使用它。为此,我们需要使用 Proxy 实例创建 Socket。之后,将目标 SocketAddress 实例传递给 Socket.connect() 方法。

请看下面的代码

Java 程序创建简单的代理服务器

TestProxyServer.java

输出

Java HTTP Proxy Server