Java实现HTTP Client的使用
Java实现HTTP Client的使用
Java中HTTP Client的发展历程
在Java的发展过程中,实现HTTP客户端功能的方式不断演进。早期,Java开发者主要使用HttpURLConnection
类,它是Java标准库中处理HTTP请求的基础工具。HttpURLConnection
自JDK 1.4开始引入,它提供了基本的HTTP请求和响应处理能力,例如设置请求方法(GET、POST等)、添加请求头、读取响应数据等。
然而,HttpURLConnection
存在一些局限性。它的API相对繁琐,特别是在处理复杂的HTTP场景,如处理重定向、设置连接超时、处理不同类型的请求体等方面,代码编写较为复杂。而且,在性能和可扩展性方面,HttpURLConnection
也不能很好地满足现代应用开发的需求。
随着Java的发展,为了更好地处理HTTP通信,Java 9引入了全新的HTTP客户端API,即java.net.http
包。这个新的HTTP客户端API设计理念更加先进,它采用了现代的异步、非阻塞I/O模型,使得HTTP请求处理更加高效,并且提供了简洁易用的API,大大简化了开发者处理HTTP通信的工作。新的HTTP客户端支持HTTP/1.1和HTTP/2协议,并且在处理复杂的HTTP场景时表现得更加灵活和强大。
使用HttpURLConnection实现HTTP Client
-
发送GET请求
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; public class HttpGetExample { public static void main(String[] args) { try { URL url = new URL("http://example.com"); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("GET"); int responseCode = connection.getResponseCode(); System.out.println("Response Code : " + responseCode); BufferedReader in = new BufferedReader( new InputStreamReader(connection.getInputStream())); String inputLine; StringBuilder response = new StringBuilder(); while ((inputLine = in.readLine()) != null) { response.append(inputLine); } in.close(); System.out.println(response.toString()); } catch (IOException e) { e.printStackTrace(); } } }
在上述代码中,首先创建一个
URL
对象,指定要访问的URL地址。然后通过openConnection
方法获取HttpURLConnection
实例,并设置请求方法为GET
。通过getResponseCode
方法获取响应状态码,通过getInputStream
方法获取响应输入流,读取响应内容。 -
发送POST请求
import java.io.BufferedReader; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import java.nio.charset.StandardCharsets; public class HttpPostExample { public static void main(String[] args) { String url = "http://example.com/api"; String params = "param1=value1¶m2=value2"; try { URL obj = new URL(url); HttpURLConnection con = (HttpURLConnection) obj.openConnection(); con.setRequestMethod("POST"); con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); con.setRequestProperty("Content-Length", String.valueOf(params.length())); con.setDoOutput(true); DataOutputStream wr = new DataOutputStream(con.getOutputStream()); wr.writeBytes(params); wr.flush(); wr.close(); int responseCode = con.getResponseCode(); System.out.println("Response Code : " + responseCode); BufferedReader in = new BufferedReader( new InputStreamReader(con.getInputStream())); String inputLine; StringBuilder response = new StringBuilder(); while ((inputLine = in.readLine()) != null) { response.append(inputLine); } in.close(); System.out.println(response.toString()); } catch (IOException e) { e.printStackTrace(); } } }
对于POST请求,除了设置请求方法为
POST
,还需要设置Content - Type
请求头,并通过DataOutputStream
将请求参数写入输出流。
使用Java 9+的HTTP Client实现HTTP请求
-
发送GET请求
import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.io.IOException; import java.util.concurrent.ExecutionException; public class Java9HttpGetExample { public static void main(String[] args) throws IOException, InterruptedException, ExecutionException { HttpClient client = HttpClient.newHttpClient(); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("http://example.com")) .GET() .build(); HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.statusCode()); System.out.println(response.body()); } }
这里通过
HttpClient.newHttpClient()
创建一个HttpClient
实例,通过HttpRequest.newBuilder
构建请求,设置请求的URI并指定请求方法为GET
。最后通过client.send
方法发送请求,并使用HttpResponse.BodyHandlers.ofString()
处理响应体,将响应内容以字符串形式返回。 -
发送POST请求
import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.nio.charset.StandardCharsets; import java.io.IOException; import java.util.concurrent.ExecutionException; public class Java9HttpPostExample { public static void main(String[] args) throws IOException, InterruptedException, ExecutionException { HttpClient client = HttpClient.newHttpClient(); String params = "param1=value1¶m2=value2"; HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("http://example.com/api")) .POST(HttpRequest.BodyPublishers.ofString(params, StandardCharsets.UTF_8)) .header("Content-Type", "application/x-www-form-urlencoded") .build(); HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.statusCode()); System.out.println(response.body()); } }
对于POST请求,使用
HttpRequest.BodyPublishers.ofString
将请求参数设置到请求体中,并设置Content - Type
请求头。
处理HTTP请求头
-
使用HttpURLConnection设置请求头
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; public class HttpHeaderExampleWithUrlConnection { public static void main(String[] args) { try { URL url = new URL("http://example.com"); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("GET"); connection.setRequestProperty("User - Agent", "Mozilla/5.0"); connection.setRequestProperty("Accept", "application/json"); int responseCode = connection.getResponseCode(); System.out.println("Response Code : " + responseCode); BufferedReader in = new BufferedReader( new InputStreamReader(connection.getInputStream())); String inputLine; StringBuilder response = new StringBuilder(); while ((inputLine = in.readLine()) != null) { response.append(inputLine); } in.close(); System.out.println(response.toString()); } catch (IOException e) { e.printStackTrace(); } } }
在
HttpURLConnection
中,通过setRequestProperty
方法设置请求头,这里设置了User - Agent
和Accept
请求头。 -
使用Java 9+的HTTP Client设置请求头
import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.io.IOException; import java.util.concurrent.ExecutionException; public class HttpHeaderExampleWithJava9Client { public static void main(String[] args) throws IOException, InterruptedException, ExecutionException { HttpClient client = HttpClient.newHttpClient(); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("http://example.com")) .GET() .header("User - Agent", "Mozilla/5.0") .header("Accept", "application/json") .build(); HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.statusCode()); System.out.println(response.body()); } }
在Java 9+的HTTP Client中,通过
header
方法设置请求头,同样设置了User - Agent
和Accept
请求头。
处理HTTP响应头
-
使用HttpURLConnection获取响应头
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import java.util.Map; public class HttpResponseHeaderExampleWithUrlConnection { public static void main(String[] args) { try { URL url = new URL("http://example.com"); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("GET"); int responseCode = connection.getResponseCode(); System.out.println("Response Code : " + responseCode); Map<String, List<String>> headers = connection.getHeaderFields(); for (String key : headers.keySet()) { System.out.println(key + " : " + headers.get(key)); } BufferedReader in = new BufferedReader( new InputStreamReader(connection.getInputStream())); String inputLine; StringBuilder response = new StringBuilder(); while ((inputLine = in.readLine()) != null) { response.append(inputLine); } in.close(); System.out.println(response.toString()); } catch (IOException e) { e.printStackTrace(); } } }
通过
HttpURLConnection
的getHeaderFields
方法获取所有响应头,它返回一个Map
,其中键是响应头名称,值是一个List
,因为可能存在多个同名的响应头。 -
使用Java 9+的HTTP Client获取响应头
import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.io.IOException; import java.util.concurrent.ExecutionException; public class HttpResponseHeaderExampleWithJava9Client { public static void main(String[] args) throws IOException, InterruptedException, ExecutionException { HttpClient client = HttpClient.newHttpClient(); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("http://example.com")) .GET() .build(); HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.statusCode()); response.headers().map().forEach((key, value) -> System.out.println(key + " : " + value)); System.out.println(response.body()); } }
在Java 9+的HTTP Client中,通过
response.headers().map()
获取响应头的Map
,并遍历输出。
处理HTTP重定向
-
HttpURLConnection处理重定向
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; public class HttpRedirectExampleWithUrlConnection { public static void main(String[] args) { try { URL url = new URL("http://redirect.example.com"); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setInstanceFollowRedirects(true); int responseCode = connection.getResponseCode(); System.out.println("Response Code : " + responseCode); BufferedReader in = new BufferedReader( new InputStreamReader(connection.getInputStream())); String inputLine; StringBuilder response = new StringBuilder(); while ((inputLine = in.readLine()) != null) { response.append(inputLine); } in.close(); System.out.println(response.toString()); } catch (IOException e) { e.printStackTrace(); } } }
在
HttpURLConnection
中,通过设置setInstanceFollowRedirects(true)
来自动处理重定向。如果设置为false
,开发者需要手动处理重定向,通过获取Location
响应头并重新发起请求。 -
Java 9+的HTTP Client处理重定向
import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.io.IOException; import java.util.concurrent.ExecutionException; public class HttpRedirectExampleWithJava9Client { public static void main(String[] args) throws IOException, InterruptedException, ExecutionException { HttpClient client = HttpClient.newHttpClient() .newBuilder() .followRedirects(HttpClient.Redirect.ALWAYS) .build(); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("http://redirect.example.com")) .GET() .build(); HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.statusCode()); System.out.println(response.body()); } }
在Java 9+的HTTP Client中,通过
HttpClient.newHttpClient().newBuilder().followRedirects(HttpClient.Redirect.ALWAYS)
设置自动处理重定向,HttpClient.Redirect
枚举还提供了NEVER
和PROMPT
等选项,用于更灵活地控制重定向处理。
设置连接超时和读取超时
-
HttpURLConnection设置超时
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; public class HttpTimeoutExampleWithUrlConnection { public static void main(String[] args) { try { URL url = new URL("http://example.com"); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("GET"); connection.setConnectTimeout(5000); // 连接超时5秒 connection.setReadTimeout(5000); // 读取超时5秒 int responseCode = connection.getResponseCode(); System.out.println("Response Code : " + responseCode); BufferedReader in = new BufferedReader( new InputStreamReader(connection.getInputStream())); String inputLine; StringBuilder response = new StringBuilder(); while ((inputLine = in.readLine()) != null) { response.append(inputLine); } in.close(); System.out.println(response.toString()); } catch (IOException e) { e.printStackTrace(); } } }
在
HttpURLConnection
中,通过setConnectTimeout
设置连接超时时间,通过setReadTimeout
设置读取超时时间,单位都是毫秒。 -
Java 9+的HTTP Client设置超时
import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.io.IOException; import java.time.Duration; import java.util.concurrent.ExecutionException; public class HttpTimeoutExampleWithJava9Client { public static void main(String[] args) throws IOException, InterruptedException, ExecutionException { HttpClient client = HttpClient.newHttpClient() .newBuilder() .connectTimeout(Duration.ofSeconds(5)) .build(); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("http://example.com")) .GET() .build(); HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.statusCode()); System.out.println(response.body()); } }
在Java 9+的HTTP Client中,通过
HttpClient.newHttpClient().newBuilder().connectTimeout(Duration.ofSeconds(5))
设置连接超时时间,这里使用Duration
类来表示时间。对于读取超时,目前Java 9+的HTTP Client没有直接提供设置读取超时的方法,但可以通过自定义BodyHandler
来实现类似功能。
处理HTTPS请求
-
使用HttpURLConnection处理HTTPS请求
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; public class HttpsExampleWithUrlConnection { public static void main(String[] args) { try { TrustManager[] trustAllCerts = new TrustManager[]{ new X509TrustManager() { public java.security.cert.X509Certificate[] getAcceptedIssuers() { return null; } public void checkClientTrusted(X509Certificate[] certs, String authType) { } public void checkServerTrusted(X509Certificate[] certs, String authType) { } } }; SSLContext sc = SSLContext.getInstance("TLS"); sc.init(null, trustAllCerts, new java.security.SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); URL url = new URL("https://example.com"); HttpsURLConnection connection = (HttpsURLConnection) url.openConnection(); connection.setRequestMethod("GET"); int responseCode = connection.getResponseCode(); System.out.println("Response Code : " + responseCode); BufferedReader in = new BufferedReader( new InputStreamReader(connection.getInputStream())); String inputLine; StringBuilder response = new StringBuilder(); while ((inputLine = in.readLine()) != null) { response.append(inputLine); } in.close(); System.out.println(response.toString()); } catch (Exception e) { e.printStackTrace(); } } }
在处理HTTPS请求时,
HttpURLConnection
需要处理SSL证书验证。上述代码通过创建一个信任所有证书的TrustManager
,并设置到SSLContext
中,然后设置HttpsURLConnection
的默认SSLSocketFactory
来实现忽略证书验证。在实际应用中,应该使用更安全的证书验证方式,例如加载合法的证书到信任库。 -
使用Java 9+的HTTP Client处理HTTPS请求
import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.io.IOException; import java.util.concurrent.ExecutionException; public class HttpsExampleWithJava9Client { public static void main(String[] args) throws IOException, InterruptedException, ExecutionException { HttpClient client = HttpClient.newHttpClient(); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://example.com")) .GET() .build(); HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.statusCode()); System.out.println(response.body()); } }
Java 9+的HTTP Client默认会进行证书验证。如果服务器使用的是合法的证书,上述代码可以直接正常工作。如果需要忽略证书验证(仅适用于开发和测试环境),可以通过自定义
HttpClient
的SslContext
来实现,类似HttpURLConnection
的处理方式,但需要更多的代码来配置。
异步HTTP请求
- Java 9+的HTTP Client异步请求
Java 9+的HTTP Client提供了异步请求的能力。通过import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.io.IOException; import java.util.concurrent.CompletableFuture; public class AsyncHttpExampleWithJava9Client { public static void main(String[] args) { HttpClient client = HttpClient.newHttpClient(); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("http://example.com")) .GET() .build(); CompletableFuture<HttpResponse<String>> future = client.sendAsync(request, HttpResponse.BodyHandlers.ofString()); future.thenApply(HttpResponse::body) .thenAccept(System.out::println) .join(); } }
sendAsync
方法发送请求,它返回一个CompletableFuture
。可以通过thenApply
和thenAccept
等方法对异步结果进行处理,这里获取响应体并打印。异步请求在处理I/O密集型操作时非常有用,可以提高应用程序的性能和响应性,避免线程阻塞。
总结不同方式的优缺点
-
HttpURLConnection
- 优点:是Java标准库的一部分,不需要额外引入依赖,广泛支持,兼容性好,在老版本的Java环境中也能使用。
- 缺点:API繁琐,处理复杂HTTP场景(如重定向、认证等)代码复杂,性能和可扩展性相对较差,在高并发场景下表现不佳。
-
Java 9+的HTTP Client
- 优点:简洁易用的API,采用现代异步、非阻塞I/O模型,性能和可扩展性好,支持HTTP/2协议,对复杂HTTP场景的处理更加灵活,并且在处理异步请求方面有很好的支持。
- 缺点:依赖Java 9及以上版本,对于使用老版本Java的项目无法使用。
在实际项目中,应根据项目的具体需求和所使用的Java版本来选择合适的HTTP客户端实现方式。如果项目需要兼容老版本Java,HttpURLConnection
可能是一个选择;而如果项目基于Java 9及以上版本,并且对性能和开发效率有较高要求,Java 9+的HTTP Client则是更好的选择。
通过以上对Java中不同HTTP客户端实现方式的介绍,开发者可以根据实际情况灵活选择,以满足项目中HTTP通信的需求。无论是简单的GET和POST请求,还是复杂的HTTPS、异步请求等场景,都能找到合适的解决方案来实现高效、可靠的HTTP通信。