Java怎么发起http请求

发布时间:2021-06-12 11:14:23 作者:小新
来源:亿速云 阅读:224
# Java怎么发起HTTP请求

HTTP请求是现代应用程序开发中最基础也最重要的功能之一。无论是调用第三方API、获取网络数据还是实现微服务间的通信,都需要使用HTTP协议。Java作为企业级开发的主流语言,提供了多种发起HTTP请求的方式。本文将全面介绍Java中发起HTTP请求的各类方法、最佳实践以及常见问题解决方案。

## 目录
1. [HTTP协议基础](#http协议基础)
2. [Java原生HTTP客户端](#java原生http客户端)
   - [HttpURLConnection](#httpurlconnection)
   - [HttpClient (Java 11+)](#httpclient-java-11)
3. [第三方HTTP客户端库](#第三方http客户端库)
   - [Apache HttpClient](#apache-httpclient)
   - [OkHttp](#okhttp)
   - [RestTemplate](#resttemplate)
   - [WebClient](#webclient)
4. [HTTP请求方法详解](#http请求方法详解)
   - [GET请求](#get请求)
   - [POST请求](#post请求)
   - [PUT/DELETE请求](#putdelete请求)
5. [请求头与参数处理](#请求头与参数处理)
6. [响应处理](#响应处理)
7. [异步HTTP请求](#异步http请求)
8. [HTTPS与证书处理](#https与证书处理)
9. [性能优化](#性能优化)
10. [常见问题与解决方案](#常见问题与解决方案)
11. [总结与建议](#总结与建议)

## HTTP协议基础

HTTP(HyperText Transfer Protocol)是应用层协议,用于分布式、协作式和超媒体信息系统的应用层协议。HTTP是无状态协议,意味着服务器不会在两个请求之间保留任何数据(状态)。

主要特点:
- 基于请求/响应模型
- 简单快速
- 灵活(可以传输任意类型数据)
- 无连接(每次连接只处理一个请求)
- 无状态

HTTP请求由以下部分组成:
1. 请求行(方法、URL、协议版本)
2. 请求头(Header)
3. 空行
4. 请求体(Body)

## Java原生HTTP客户端

### HttpURLConnection

`HttpURLConnection`是Java最基础的HTTP客户端,存在于`java.net`包中,自JDK1.1就已存在。

```java
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

public class HttpURLConnectionExample {
    public static void main(String[] args) throws Exception {
        URL url = new URL("https://example.com/api");
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        
        // 设置请求方法
        connection.setRequestMethod("GET");
        
        // 设置请求头
        connection.setRequestProperty("User-Agent", "Java HTTP Client");
        connection.setRequestProperty("Accept", "application/json");
        
        // 获取响应码
        int responseCode = connection.getResponseCode();
        System.out.println("Response Code: " + responseCode);
        
        // 读取响应内容
        try (BufferedReader in = new BufferedReader(
                new InputStreamReader(connection.getInputStream()))) {
            String line;
            StringBuilder response = new StringBuilder();
            while ((line = in.readLine()) != null) {
                response.append(line);
            }
            System.out.println("Response: " + response.toString());
        }
        
        // 关闭连接
        connection.disconnect();
    }
}

优点: - JDK内置,无需额外依赖 - 简单请求场景下使用方便

缺点: - API设计较为底层,使用繁琐 - 缺乏连接池管理 - 错误处理不够友好 - 不支持HTTP/2

HttpClient (Java 11+)

Java 11引入了新的HttpClient,位于java.net.http包中,支持HTTP/2和WebSocket,提供了同步和异步两种调用方式。

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class HttpClientExample {
    public static void main(String[] args) throws Exception {
        // 创建HttpClient实例
        HttpClient client = HttpClient.newHttpClient();
        
        // 构建请求
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://example.com/api"))
                .header("Content-Type", "application/json")
                .GET()
                .build();
        
        // 发送同步请求
        HttpResponse<String> response = client.send(
                request, HttpResponse.BodyHandlers.ofString());
        
        System.out.println("Status code: " + response.statusCode());
        System.out.println("Response body: " + response.body());
        
        // 异步请求示例
        client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
                .thenApply(HttpResponse::body)
                .thenAccept(System.out::println)
                .join();
    }
}

优点: - 现代API设计,使用流畅 - 支持HTTP/2 - 内置异步支持 - 更好的性能

缺点: - 需要Java 11+环境 - 某些高级功能仍需第三方库

第三方HTTP客户端库

Apache HttpClient

Apache HttpClient是功能最全面的Java HTTP客户端之一,提供了丰富的功能和配置选项。

Maven依赖:

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.13</version>
</dependency>

使用示例:

import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

public class ApacheHttpClientExample {
    public static void main(String[] args) throws Exception {
        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
            HttpGet request = new HttpGet("https://example.com/api");
            
            // 设置请求头
            request.addHeader("User-Agent", "Apache HttpClient");
            
            try (CloseableHttpResponse response = httpClient.execute(request)) {
                // 获取响应状态
                System.out.println(response.getStatusLine().toString());
                
                // 获取响应内容
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    String result = EntityUtils.toString(entity);
                    System.out.println(result);
                }
            }
        }
    }
}

特点: - 成熟的HTTP客户端实现 - 支持连接池管理 - 支持多种认证机制 - 支持HTTPS - 支持自定义拦截器

OkHttp

OkHttp是由Square公司开发的现代HTTP客户端,Android开发中广泛使用,但也适用于Java应用。

Maven依赖:

<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>4.9.3</version>
</dependency>

使用示例:

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

public class OkHttpExample {
    public static void main(String[] args) throws Exception {
        OkHttpClient client = new OkHttpClient();
        
        Request request = new Request.Builder()
                .url("https://example.com/api")
                .addHeader("Accept", "application/json")
                .build();
        
        try (Response response = client.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                throw new RuntimeException("Unexpected code " + response);
            }
            
            System.out.println(response.body().string());
        }
    }
}

特点: - 简洁的API设计 - 自动GZIP压缩 - 响应缓存 - 连接池复用 - 支持HTTP/2

RestTemplate

RestTemplate是Spring框架提供的HTTP客户端,虽然已被标记为过时(推荐使用WebClient),但在许多项目中仍有使用。

import org.springframework.web.client.RestTemplate;

public class RestTemplateExample {
    public static void main(String[] args) {
        RestTemplate restTemplate = new RestTemplate();
        String url = "https://example.com/api";
        
        // GET请求
        String response = restTemplate.getForObject(url, String.class);
        System.out.println(response);
        
        // POST请求
        // String requestBody = "{\"key\":\"value\"}";
        // String postResponse = restTemplate.postForObject(url, requestBody, String.class);
    }
}

特点: - 与Spring生态集成良好 - 自动对象映射(JSON/XML) - 支持OAuth等安全机制

WebClient

WebClient是Spring 5引入的响应式HTTP客户端,支持异步和非阻塞IO。

Maven依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

使用示例:

import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;

public class WebClientExample {
    public static void main(String[] args) {
        WebClient client = WebClient.create("https://example.com");
        
        Mono<String> response = client.get()
                .uri("/api")
                .retrieve()
                .bodyToMono(String.class);
        
        // 阻塞获取结果(实际应用中通常不阻塞)
        System.out.println(response.block());
    }
}

特点: - 响应式编程模型 - 支持HTTP/2 - 非阻塞IO - 流式处理 - 与Spring生态深度集成

HTTP请求方法详解

GET请求

GET是最常见的HTTP方法,用于获取资源。

// 使用HttpURLConnection
URL url = new URL("https://example.com/api?param1=value1&param2=value2");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");

// 使用HttpClient
HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create("https://example.com/api?param1=value1&param2=value2"))
        .GET()
        .build();

POST请求

POST用于提交数据到服务器。

// 使用HttpURLConnection
URL url = new URL("https://example.com/api");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setDoOutput(true);

String postData = "param1=value1&param2=value2";
try (OutputStream os = connection.getOutputStream()) {
    byte[] input = postData.getBytes("utf-8");
    os.write(input, 0, input.length);
}

// 使用HttpClient
String requestBody = "{\"key\":\"value\"}";
HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create("https://example.com/api"))
        .header("Content-Type", "application/json")
        .POST(HttpRequest.BodyPublishers.ofString(requestBody))
        .build();

PUT/DELETE请求

PUT用于更新资源,DELETE用于删除资源。

// PUT请求示例
HttpRequest putRequest = HttpRequest.newBuilder()
        .uri(URI.create("https://example.com/api/123"))
        .header("Content-Type", "application/json")
        .PUT(HttpRequest.BodyPublishers.ofString("{\"name\":\"new value\"}"))
        .build();

// DELETE请求示例
HttpRequest deleteRequest = HttpRequest.newBuilder()
        .uri(URI.create("https://example.com/api/123"))
        .DELETE()
        .build();

请求头与参数处理

设置请求头

// HttpURLConnection
connection.setRequestProperty("Content-Type", "application/json");
connection.setRequestProperty("Authorization", "Bearer token");

// HttpClient
HttpRequest request = HttpRequest.newBuilder()
        .header("Content-Type", "application/json")
        .header("Authorization", "Bearer token")
        .build();

查询参数处理

// 手动构建查询字符串
String query = "param1=" + URLEncoder.encode("value1", StandardCharsets.UTF_8) +
        "¶m2=" + URLEncoder.encode("value2", StandardCharsets.UTF_8);

// 使用URIBuilder (Apache HttpClient)
URI uri = new URIBuilder("https://example.com/api")
        .addParameter("param1", "value1")
        .addParameter("param2", "value2")
        .build();

表单参数处理

// 使用URL编码表单
String form = "username=" + URLEncoder.encode("user", "UTF-8") +
        "&password=" + URLEncoder.encode("pass", "UTF-8");

// 使用MultiValueMap (Spring)
MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
formData.add("username", "user");
formData.add("password", "pass");

响应处理

处理响应状态

// HttpURLConnection
int status = connection.getResponseCode();
if (status == HttpURLConnection.HTTP_OK) {
    // 处理成功响应
} else {
    // 处理错误
}

// HttpClient
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() == 200) {
    System.out.println(response.body());
} else {
    System.out.println("Error: " + response.statusCode());
}

处理JSON响应

// 使用Jackson
ObjectMapper mapper = new ObjectMapper();
MyObject obj = mapper.readValue(response.body(), MyObject.class);

// 使用Gson
Gson gson = new Gson();
MyObject obj = gson.fromJson(response.body(), MyObject.class);

处理二进制响应

// 获取字节数组
byte[] bytes = response.body().getBytes();

// 保存为文件
try (FileOutputStream fos = new FileOutputStream("file.png")) {
    fos.write(bytes);
}

异步HTTP请求

使用HttpClient异步请求

HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create("https://example.com/api"))
        .build();

client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
        .thenApply(HttpResponse::body)
        .thenAccept(System.out::println)
        .exceptionally(e -> {
            System.err.println("Error: " + e.getMessage());
            return null;
        });

// 主线程继续执行其他任务
System.out.println("Request sent asynchronously");

使用WebClient异步请求

WebClient client = WebClient.create("https://example.com");

client.get()
        .uri("/api")
        .retrieve()
        .bodyToMono(String.class)
        .subscribe(
                response -> System.out.println("Response: " + response),
                error -> System.err.println("Error: " + error.getMessage())
        );

HTTPS与证书处理

信任所有证书(开发环境)

// 创建信任所有证书的HttpClient
HttpClient client = HttpClient.newBuilder()
        .sslContext(createUnsafeSSLContext())
        .build();

private static SSLContext createUnsafeSSLContext() throws Exception {
    TrustManager[] trustAllCerts = new TrustManager[]{
        new X509TrustManager() {
            public void checkClientTrusted(X509Certificate[] chain, String authType) {}
            public void checkServerTrusted(X509Certificate[] chain, String authType) {}
            public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
        }
    };
    
    SSLContext sslContext = SSLContext.getInstance("TLS");
    sslContext.init(null, trustAllCerts, new SecureRandom());
    return sslContext;
}

自定义证书信任

// 加载自定义信任库
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
try (InputStream is = new FileInputStream("truststore.jks")) {
    keyStore.load(is, "password".toCharArray());
}

TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(keyStore);

SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);

HttpClient client = HttpClient.newBuilder()
        .sslContext(sslContext)
        .build();

性能优化

连接池管理

// Apache HttpClient连接池配置
PoolingHttpClientConnectionManager connectionManager = 
        new PoolingHttpClientConnectionManager();
connectionManager.setMaxTotal(200); // 最大连接数
connectionManager.setDefaultMaxPerRoute(20); // 每个路由最大连接数

CloseableHttpClient httpClient = HttpClients.custom()
        .setConnectionManager(connectionManager)
        .build();

请求超时设置

// HttpClient超时设置
HttpClient client = HttpClient.newBuilder()
        .connectTimeout(Duration.ofSeconds(10))
        .build();

// Apache HttpClient超时设置
RequestConfig config = RequestConfig.custom()
        .setConnectTimeout(5000)
        .setSocketTimeout(5000)
        .build();

CloseableHttpClient httpClient = HttpClients.custom()
        .setDefaultRequestConfig(config)
        .build();

响应缓存

// OkHttp缓存配置
int cacheSize = 10 * 1024 * 1024; // 10MB
Cache cache = new Cache(new File("http-cache"), cacheSize);

OkHttpClient client = new OkHttpClient.Builder()
        .cache(cache)
        .build();

常见问题与解决方案

1. 连接超时问题

问题表现java.net.ConnectException: Connection timed out

解决方案: - 检查网络连接 - 增加连接超时时间 - 检查目标服务器是否可达

// 设置连接超时
HttpClient client = HttpClient.newBuilder()
        .connectTimeout(Duration.ofSeconds(30))
        .build();

2. SSL证书验证失败

问题表现javax.net.ssl.SSLHandshakeException

解决方案: - 导入正确的证书 - 开发环境可以临时禁用证书验证(不推荐生产环境使用)

3. 响应解析错误

问题表现com.fasterxml.jackson.core.JsonParseException

解决方案: - 检查响应内容是否符合预期格式 - 添加错误处理逻辑

try {
    ObjectMapper mapper = new ObjectMapper();
    MyObject obj = mapper.readValue(response, MyObject.class);
} catch (JsonProcessingException e) {
    System.err.println("Failed to parse JSON: " + e.getMessage());
    // 处理错误情况
}

4. 连接泄漏

问题表现:应用逐渐变慢,最终耗尽连接资源

解决方案: - 确保所有资源都被正确关闭 -

推荐阅读:
  1. iphone发起http请求源码
  2. golang 发起http请求

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

java

上一篇:scala怎么匹配自定义泛型类型

下一篇:怎么为WPF数据网格创建自定义筛选器编辑器对话框

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》