HTTP(HyperText Transfer Protocol,超文本传输协议)是一种应用层协议,用于在客户端和服务器之间传输超文本(如HTML)。它是Web数据通信的基础,采用请求-响应模型。
方法 | 用途 |
---|---|
GET | 获取资源(参数在URL中) |
POST | 提交数据(参数在请求体) |
PUT | 更新资源 |
DELETE | 删除资源 |
200 OK
:请求成功404 Not Found
:资源不存在500 Internal Server Error
:服务器错误GET /index.html HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0
HTTP/1.1 200 OK
Content-Type: text/html
...
// 使用HttpURLConnection发送GET请求示例
URL url = new URL("http://example.com/api");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
Content-Type
头部SocketTimeoutException
http://example.com?name=value
。// GET 请求示例(HttpURLConnection)
URL url = new URL("http://example.com?param1=value1");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
// POST 请求示例(HttpURLConnection)
URL url = new URL("http://example.com");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setDoOutput(true);
try (OutputStream os = conn.getOutputStream()) {
os.write("param1=value1".getBytes());
}
Content-Type
(如 application/x-www-form-urlencoded
)。请求头是 HTTP 请求的一部分,用于传递客户端(如浏览器或 Java 程序)向服务器发送的附加信息。它由一系列键值对组成,每个键值对提供特定的元数据。
application/json
或 application/x-www-form-urlencoded
)。Bearer token
)。Cache-Control
)。Content-Type
)。请求体是 HTTP 请求中携带实际数据的部分,通常用于 POST、PUT 等请求方法。GET 请求一般没有请求体。
application/x-www-form-urlencoded
(如 key1=value1&key2=value2
)。application/json
(如 {"key": "value"}
)。multipart/form-data
。Content-Type
与请求体格式匹配。import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
public class HttpExample {
public static void main(String[] args) throws Exception {
// 1. 创建 HttpClient
HttpClient client = HttpClient.newHttpClient();
// 2. 构建请求体(JSON 格式)
String requestBody = "{\"username\":\"admin\",\"password\":\"123\"}";
// 3. 创建 HttpRequest,设置请求头和请求体
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://example.com/api/login"))
.header("Content-Type", "application/json")
.header("Authorization", "Bearer abc123")
.POST(HttpRequest.BodyPublishers.ofString(requestBody))
.build();
// 4. 发送请求并获取响应
HttpResponse<String> response =
client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println("响应状态码: " + response.statusCode());
System.out.println("响应体: " + response.body());
}
}
.header()
方法设置请求头。BodyPublishers.ofString()
设置请求体。Content-Type
头。URL 编码(Percent-Encoding)是一种将特殊字符转换为 %
后跟两位十六进制数的格式的机制。例如,空格会被编码为 %20
。
URL 中只能包含 ASCII 字符集中的合法字符(如字母、数字和部分符号)。如果 URL 包含非 ASCII 字符(如中文)或保留字符(如 ?
, &
, =
),必须进行编码以避免歧义或解析错误。
%20
/
:%2F
?
:%3F
&
:%26
=
:%3D
中
编码为 %E4%B8%AD
URLEncoder
类Java 提供 java.net.URLEncoder
类用于编码 URL 参数:
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
String encodedValue = URLEncoder.encode("参数值", StandardCharsets.UTF_8);
// 输出:%E5%8F%82%E6%95%B0%E5%80%BC
String url = "http://example.com/search?q=" + URLEncoder.encode("Java 教程", "UTF-8");
GET 请求的参数直接拼接在 URL 后,格式为:
http://example.com/api?key1=value1&key2=value2
需对 key
和 value
分别编码。
String baseUrl = "http://example.com/search";
String query = "Java 网络编程";
int page = 2;
String encodedQuery = URLEncoder.encode(query, StandardCharsets.UTF_8);
String urlWithParams = baseUrl + "?q=" + encodedQuery + "&page=" + page;
// 结果:http://example.com/search?q=Java%20%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B&page=2
POST 请求的表单数据也需要编码,格式与 GET 的查询字符串相同,但通过请求体发送。
import java.net.HttpURLConnection;
import java.io.OutputStream;
String param1 = "value1";
String param2 = "中文";
String encodedData = "key1=" + URLEncoder.encode(param1, StandardCharsets.UTF_8) +
"&key2=" + URLEncoder.encode(param2, StandardCharsets.UTF_8);
HttpURLConnection conn = (HttpURLConnection) new URL("http://example.com/api").openConnection();
conn.setRequestMethod("POST");
conn.setDoOutput(true);
try (OutputStream os = conn.getOutputStream()) {
os.write(encodedData.getBytes(StandardCharsets.UTF_8));
}
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
如 &
未编码会错误分割参数:
// 错误:未编码 &
String badUrl = "http://example.com?name=A&B&age=20";
// 正确:
String goodUrl = "http://example.com?name=A%26B&age=20";
HTTP 状态码是服务器对客户端请求的响应标识,由 3 位数字组成,分为 5 类:
HttpURLConnection
获取状态码URL url = new URL("https://example.com/api");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
int statusCode = conn.getResponseCode(); // 获取状态码
if (statusCode == 200) {
// 处理成功响应
InputStream inputStream = conn.getInputStream();
// 读取响应数据...
} else {
// 处理错误响应
InputStream errorStream = conn.getErrorStream();
// 读取错误信息...
}
HttpClient
(Java 11+)处理响应HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://example.com/api"))
.build();
HttpResponse<String> response = client.send(
request, HttpResponse.BodyHandlers.ofString());
int statusCode = response.statusCode();
String body = response.body(); // 获取响应体
if (statusCode == 200) {
System.out.println("响应数据: " + body);
} else {
System.out.println("请求失败,状态码: " + statusCode);
}
HttpURLConnection
会自动跟随重定向,可通过 setInstanceFollowRedirects(false)
禁用。getErrorStream()
用于 4xx/5xx 错误,getInputStream()
用于成功响应。InputStream
和连接(conn.disconnect()
)。try {
URL url = new URL("https://example.com/api");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
int statusCode = conn.getResponseCode();
if (statusCode >= 200 && statusCode < 300) {
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(conn.getInputStream()))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}
} else {
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(conn.getErrorStream()))) {
String line;
while ((line = reader.readLine()) != null) {
System.err.println(line);
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
java.net.URL
发送 GET 请求java.net.URL
是 Java 标准库中用于表示统一资源定位符的类,可用于打开连接并读取网络资源。通过 URL.openConnection()
方法可以获取 URLConnection
对象,进而发送 HTTP GET 请求。
URL
对象URLConnection
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
public class GetRequestExample {
public static void main(String[] args) {
try {
// 1. 创建URL对象
URL url = new URL("https://example.com/api?param1=value1");
// 2. 打开连接
URLConnection connection = url.openConnection();
// 3. 设置请求属性(可选)
connection.setRequestProperty("User-Agent", "Java Client");
connection.setConnectTimeout(5000);
connection.setReadTimeout(5000);
// 4. 获取响应
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(connection.getInputStream()))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
MalformedURLException
和 IOException
?key=value&...
connection.getHeaderFields()
HttpURLConnection
发送 POST 请求HttpURLConnection
是 Java 标准库中用于发送 HTTP 请求的核心类,支持 GET、POST 等 HTTP 方法。通过它可以直接与服务器交互,发送请求并接收响应。
URL.openConnection()
获取 HttpURLConnection
实例。setRequestMethod("POST")
。setDoOutput(true)
允许向服务器写入数据。Content-Type
(表单或 JSON)。import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
public class PostExample {
public static void main(String[] args) throws IOException {
String url = "https://example.com/api";
String postData = "username=test&password=123456";
// 1. 创建连接
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
// 2. 设置请求方法
conn.setRequestMethod("POST");
// 3. 启用输出流并设置请求头
conn.setDoOutput(true);
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
// 4. 发送数据
try (OutputStream os = conn.getOutputStream()) {
byte[] input = postData.getBytes(StandardCharsets.UTF_8);
os.write(input, 0, input.length);
}
// 5. 读取响应
try (BufferedReader br = new BufferedReader(
new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8))) {
StringBuilder response = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
response.append(line);
}
System.out.println("响应内容: " + response);
}
conn.disconnect(); // 关闭连接
}
}
IOException
,处理网络或流错误。try-with-resources
确保流自动关闭。setConnectTimeout()
和 setReadTimeout()
避免阻塞。setInstanceFollowRedirects(false)
禁用。SSLContext
)。HTTP 请求头(Headers)是客户端和服务器之间传递的元数据,用于控制请求和响应的行为。在发送 GET 或 POST 请求时,设置合适的请求头参数可以优化通信,例如指定内容类型、认证信息或缓存策略。
application/json
、application/x-www-form-urlencoded
)。application/json
)。Bearer token
)。no-cache
)。HttpURLConnection
import java.net.HttpURLConnection;
import java.net.URL;
public class HttpExample {
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("Content-Type", "application/json");
connection.setRequestProperty("Authorization", "Bearer your_token");
// 发送请求并处理响应
int responseCode = connection.getResponseCode();
System.out.println("Response Code: " + responseCode);
}
}
HttpClient
(Java 11+)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 client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://example.com/api"))
.header("Content-Type", "application/json")
.header("Authorization", "Bearer your_token")
.GET() // 或 .POST(HttpRequest.BodyPublishers.ofString("请求体"))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println("Response Body: " + response.body());
}
}
Content-Type
)。setRequestProperty
会覆盖同名头,而 addRequestProperty
(部分库支持)可添加多个值。通过合理设置请求头,可以确保请求被正确处理,并实现身份验证、内容协商等功能。
在Java中发送HTTP请求后,服务器返回的响应通常以数据流(InputStream)的形式传输。处理响应数据流是指从HTTP响应中读取、解析和转换这些原始字节数据为可用的格式(如字符串、JSON对象等)。
HttpURLConnection.getInputStream()
- 获取原始输入流BufferedReader
- 用于高效读取文本数据InputStream
/OutputStream
- 用于处理二进制数据HttpURLConnection connection = (HttpURLConnection) url.openConnection();
try (InputStream inputStream = connection.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
StringBuilder response = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
response.append(line);
}
System.out.println(response.toString());
}
try (InputStream in = connection.getInputStream();
FileOutputStream out = new FileOutputStream("output.file")) {
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = in.read(buffer)) != -1) {
out.write(buffer, 0, bytesRead);
}
}
对于JSON响应,可结合Jackson/Gson:
InputStream input = connection.getInputStream();
MyData data = new ObjectMapper().readValue(input, MyData.class);
在Java发送HTTP请求时,异常处理和资源释放是确保程序健壮性和资源高效利用的关键环节。异常处理指捕获并处理网络请求中可能出现的异常(如超时、连接失败等),资源释放指在使用完毕后关闭连接、流等系统资源,防止内存泄漏。
InputStream
或HttpURLConnection
导致连接泄漏。finally
块中释放资源,或在Java 7之前未手动关闭资源。catch
块中直接捕获Exception
而不区分具体异常类型。HttpURLConnection
)HttpURLConnection connection = null;
InputStream inputStream = null;
try {
URL url = new URL("https://example.com/api");
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
inputStream = connection.getInputStream();
// 处理输入流数据...
} catch (IOException e) {
System.err.println("请求失败: " + e.getMessage());
} finally {
if (inputStream != null) {
try {
inputStream.close(); // 关闭输入流
} catch (IOException e) {
System.err.println("关闭输入流失败: " + e.getMessage());
}
}
if (connection != null) {
connection.disconnect(); // 断开连接
}
}
try (InputStream inputStream = new URL("https://example.com/api").openStream()) {
// 自动关闭资源
// 处理输入流数据...
} catch (IOException e) {
System.err.println("请求失败: " + e.getMessage());
}
AutoCloseable
接口),自动释放资源。MalformedURLException
、SocketTimeoutException
等具体异常。URI
:目标地址(如 https://example.com/api
)。HttpMethod
:GET/POST/PUT/DELETE 等。Headers
:Content-Type、Authorization 等。BodyPublisher
:请求体数据(如 JSON 字符串)。statusCode()
:获取状态码(200、404 等)。body()
:获取响应体(字符串、字节数组等)。headers()
:读取响应头(如 Content-Length)。HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(10)) // 连接超时
.followRedirects(HttpClient.Redirect.NORMAL) // 重定向策略
.version(HttpClient.Version.HTTP_2) // HTTP 版本
.build();
ofString()
:将响应体转为字符串。ofByteArray()
:转为字节数组。ofFile(Path)
:直接保存到文件。HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://example.com/api"))
.GET()
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
HttpClient
是 Java 中用于发送 HTTP 请求的核心类,属于 java.net.http
包(JDK 11+)或第三方库(如 Apache HttpClient)。它负责管理连接、发送请求并处理响应。
// 创建实例(默认配置)
HttpClient client = HttpClient.newHttpClient();
// 自定义配置(超时、代理等)
HttpClient customClient = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(10))
.followRedirects(HttpClient.Redirect.NORMAL)
.build();
<dependency>
<groupId>org.apache.httpcomponentsgroupId>
<artifactId>httpclientartifactId>
<version>4.5.13version>
dependency>
// 创建实例
CloseableHttpClient client = HttpClients.createDefault();
// 自定义配置
CloseableHttpClient customClient = HttpClients.custom()
.setConnectionTimeToLive(10, TimeUnit.SECONDS)
.setDefaultRequestConfig(RequestConfig.custom()
.setConnectTimeout(5000)
.build())
.build();
HttpClient
实例通常设计为线程安全,建议复用而非频繁创建。close()
释放连接。PoolingHttpClientConnectionManager
)。HttpClient client = HttpClient.newBuilder()
.version(HttpClient.Version.HTTP_2) // 指定HTTP协议版本
.connectTimeout(Duration.ofSeconds(5))
.build();
GET 请求对象是用于向服务器请求数据的 HTTP 请求方式。它通过 URL 传递参数,参数以键值对的形式附加在 URL 后面,通常用于获取资源。
java.net.HttpURLConnection
URL url = new URL("https://example.com/api?param1=value1¶m2=value2");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
int responseCode = connection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
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());
}
java.net.http.HttpClient
(Java 11+)HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://example.com/api?param1=value1¶m2=value2"))
.GET()
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
URLEncoder.encode()
// 构建带参数的 GET 请求 URL
String baseUrl = "https://example.com/api";
Map<String, String> params = new HashMap<>();
params.put("name", "张三");
params.put("age", "25");
StringBuilder urlBuilder = new StringBuilder(baseUrl).append("?");
for (Map.Entry<String, String> entry : params.entrySet()) {
urlBuilder.append(URLEncoder.encode(entry.getKey(), "UTF-8"))
.append("=")
.append(URLEncoder.encode(entry.getValue(), "UTF-8"))
.append("&");
}
// 删除最后一个"&"
String finalUrl = urlBuilder.substring(0, urlBuilder.length() - 1);
POST 请求是 HTTP 协议中的一种请求方法,用于向服务器提交数据。与 GET 请求不同,POST 请求将数据放在请求体(Body)中发送,而不是附加在 URL 上。请求实体(Request Entity)是指 POST 请求中携带的数据部分,通常以 JSON、表单数据或二进制形式传输。
multipart/form-data
格式传输文件。application/json
或 application/x-www-form-urlencoded
。HttpURLConnection
发送 JSON 数据import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
public class PostJsonExample {
public static void main(String[] args) throws Exception {
URL url = new URL("https://api.example.com/data");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json");
conn.setDoOutput(true);
String jsonInput = "{\"name\":\"John\", \"age\":30}";
try (OutputStream os = conn.getOutputStream()) {
byte[] input = jsonInput.getBytes("utf-8");
os.write(input, 0, input.length);
}
int responseCode = conn.getResponseCode();
System.out.println("Response Code: " + responseCode);
}
}
HttpClient
(Java 11+)发送表单数据import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
public class PostFormExample {
public static void main(String[] args) throws Exception {
String formData = "username=test&password=123456";
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com/login"))
.header("Content-Type", "application/x-www-form-urlencoded")
.POST(HttpRequest.BodyPublishers.ofString(formData))
.build();
HttpResponse<String> response = client.send(
request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
}
}
import okhttp3.*;
public class MultipartExample {
public static void main(String[] args) throws Exception {
OkHttpClient client = new OkHttpClient();
RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("file", "test.txt",
RequestBody.create(new File("test.txt"), MediaType.parse("text/plain")))
.build();
Request request = new Request.Builder()
.url("https://api.example.com/upload")
.post(requestBody)
.build();
try (Response response = client.newCall(request).execute()) {
System.out.println(response.body().string());
}
}
}
在 Java 中,发送 HTTP 请求(GET、POST 等)后,需要执行请求并获取服务器返回的响应数据。以下是详细说明:
HttpURLConnection
// 执行 GET 请求并获取响应
URL url = new URL("https://example.com/api");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
// 获取响应状态码
int responseCode = conn.getResponseCode();
System.out.println("Response Code: " + responseCode);
// 读取响应内容
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String inputLine;
StringBuilder response = new StringBuilder();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
System.out.println("Response Body: " + response.toString());
HttpClient
(Java 11+)HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://example.com/api"))
.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());
IOException
。InputStream
、BufferedReader
等资源。HttpURLConnection
默认自动处理,可通过 setInstanceFollowRedirects(false)
禁用)。Content-Type
、Content-Length
)。连接池是一种用于管理网络连接(如数据库连接、HTTP连接)的技术,它预先创建并维护一组可复用的连接对象。当应用程序需要连接时,从池中获取;使用完毕后归还,避免频繁创建和销毁连接的开销。
// 创建连接池管理器
PoolingHttpClientConnectionManager connManager =
new PoolingHttpClientConnectionManager();
// 设置最大连接数
connManager.setMaxTotal(100);
// 设置每个路由的最大连接数
connManager.setDefaultMaxPerRoute(20);
// 设置空闲连接超时
connManager.setValidateAfterInactivity(30000);
// 创建HttpClient
CloseableHttpClient httpClient = HttpClients.custom()
.setConnectionManager(connManager)
.build();
// 使用示例
try (CloseableHttpResponse response = httpClient.execute(new HttpGet("http://example.com"))) {
// 处理响应
} finally {
httpClient.close();
}
Request.Builder
和 Response
提供流畅的 API 设计。Callback
)。CacheControl
)。OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://api.example.com/data")
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onResponse(Call call, Response response) throws IOException {
System.out.println(response.body().string());
}
@Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
});
Response
和 ResponseBody
需手动关闭(或使用 try-with-resources)。OkHttpClient.Builder
设置合理超时时间。同步请求是指客户端发送请求后,必须等待服务器响应并处理完成后才能继续执行后续代码的请求方式。在Java中,同步请求会阻塞当前线程直到收到响应。
// GET请求示例
URL url = new URL("http://example.com/api?param=value");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
// 同步等待响应
int responseCode = conn.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
BufferedReader in = new BufferedReader(
new InputStreamReader(conn.getInputStream()));
String inputLine;
StringBuilder response = new StringBuilder();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
System.out.println(response.toString());
}
conn.disconnect();
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("http://example.com/api"))
.build();
// 同步发送
HttpResponse<String> response = client.send(
request,
HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode());
System.out.println(response.body());
conn.setConnectTimeout(5000); // 5秒连接超时
conn.setReadTimeout(10000); // 10秒读取超时
异步回调处理是指在发起网络请求后,不阻塞当前线程,而是通过回调函数在请求完成时处理响应结果。这种方式避免了线程阻塞,提高了程序的并发性能。
ExecutorService executor = Executors.newFixedThreadPool(5);
executor.execute(() -> {
try {
URL url = new URL("https://example.com/api");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
// 异步读取响应
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(conn.getInputStream()))) {
StringBuilder response = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
response.append(line);
}
// 回调处理
handleResponse(response.toString());
}
} catch (Exception e) {
handleError(e);
}
});
void handleResponse(String response) {
// 处理响应逻辑
}
void handleError(Exception e) {
// 处理错误逻辑
}
CompletableFuture.supplyAsync(() -> {
try {
URL url = new URL("https://example.com/api");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// ...请求设置...
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(conn.getInputStream()))) {
return reader.lines().collect(Collectors.joining());
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}).thenAccept(response -> {
// 成功回调
System.out.println("Response: " + response);
}).exceptionally(ex -> {
// 异常回调
System.out.println("Error: " + ex.getMessage());
return null;
});
Form 表单提交是 HTML 中用于向服务器发送数据的一种方式,通常用于用户输入数据的提交。表单通过 标签定义,可以包含输入框、下拉框、按钮等控件。表单提交时,浏览器会将用户输入的数据打包并发送到指定的服务器地址。
GET 请求:
<form action="/login" method="GET">
<input type="text" name="username" />
<input type="password" name="password" />
<input type="submit" value="Submit" />
form>
/login?username=xxx&password=xxx
。POST 请求:
<form action="/login" method="POST">
<input type="text" name="username" />
<input type="password" name="password" />
<input type="submit" value="Submit" />
form>
安全性:
编码类型(enctype):
application/x-www-form-urlencoded
,适合普通文本数据。multipart/form-data
:<form action="/upload" method="POST" enctype="multipart/form-data">
<input type="file" name="file" />
<input type="submit" value="Upload" />
form>
表单控件:
name
属性,否则数据不会被提交。required
属性可以强制用户填写某些字段。// 使用 Servlet 接收 POST 表单数据
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) {
String username = request.getParameter("username");
String password = request.getParameter("password");
// 处理业务逻辑
}
}
混淆 GET 和 POST:
忽略编码问题:
<meta charset="UTF-8">
文件上传未设置 enctype:
enctype="multipart/form-data"
,否则文件内容无法正确传输。JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,常用于前后端数据传输。在 HTTP 请求中,JSON 可以作为请求体(Request Body)提交给服务器,通常用于 POST、PUT 等非幂等请求。
application/json
,否则服务器可能无法正确解析。import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class JsonPostExample {
public static void main(String[] args) throws Exception {
// JSON 数据
String jsonData = "{\"name\":\"John\", \"age\":30}";
// 创建 HttpClient
HttpClient client = HttpClient.newHttpClient();
// 创建 HttpRequest
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://example.com/api/users"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(jsonData))
.build();
// 发送请求并获取响应
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println("Response Code: " + response.statusCode());
System.out.println("Response Body: " + response.body());
}
}
Jackson
或 Gson
将 Java 对象转换为 JSON 字符串。import com.fasterxml.jackson.databind.ObjectMapper;
public class User {
private String name;
private int age;
// Getters and Setters
}
public class JsonWithJackson {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
User user = new User();
user.setName("John");
user.setAge(30);
// Java 对象转 JSON
String jsonData = mapper.writeValueAsString(user);
System.out.println("JSON: " + jsonData);
// JSON 转 Java 对象
User parsedUser = mapper.readValue(jsonData, User.class);
System.out.println("User: " + parsedUser.getName());
}
}
文件上传是指客户端(如浏览器)将本地文件通过HTTP协议传输到服务器的过程。通常使用multipart/form-data
编码格式,区别于普通的application/x-www-form-urlencoded
表单提交。
前端准备:
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="file">
<button type="submit">上传button>
form>
关键点:必须设置enctype="multipart/form-data"
后端处理(以Spring Boot为例):
@PostMapping("/upload")
public String handleUpload(@RequestParam("file") MultipartFile file) {
if (!file.isEmpty()) {
try {
byte[] bytes = file.getBytes();
Path path = Paths.get("uploads/" + file.getOriginalFilename());
Files.write(path, bytes);
return "上传成功";
} catch (IOException e) {
return "上传失败";
}
}
return "文件为空";
}
// 前端分片处理
const chunkSize = 5 * 1024 * 1024; // 5MB
const chunks = Math.ceil(file.size / chunkSize);
// 服务端检查已上传分片
@GetMapping("/checkChunk")
public boolean checkChunk(@RequestParam String fileMd5,
@RequestParam int chunkIndex) {
return FileUtils.checkChunkExists(fileMd5, chunkIndex);
}
文件类型校验:
String contentType = file.getContentType();
if (!Arrays.asList("image/jpeg", "image/png").contains(contentType)) {
throw new IllegalArgumentException("非法文件类型");
}
存储路径安全:
String safeFilename = FilenameUtils.getName(file.getOriginalFilename());
Path path = Paths.get("/secure/upload/dir", safeFilename);
病毒扫描:
if (virusScanner.scan(file.getBytes())) {
throw new SecurityException("检测到恶意文件");
}
使用NIO进行文件写入:
Files.copy(file.getInputStream(), path, StandardCopyOption.REPLACE_EXISTING);
异步处理:
@Async
public void asyncUpload(MultipartFile file) {
// 上传逻辑
}
文件名乱码:
String filename = new String(file.getOriginalFilename()
.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
临时文件清理:
@Scheduled(fixedRate = 3600000)
public void cleanTempFiles() {
// 删除超过24小时的临时文件
}
拦截器(Interceptor)是一种在请求处理过程中插入额外逻辑的机制,常用于对请求进行预处理或后处理。以下是拦截器的常见使用场景:
Access-Control-Allow-Origin
等Header,解决前端跨域问题。public class AuthInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 权限校验逻辑
if (request.getSession().getAttribute("user") == null) {
response.sendRedirect("/login");
return false; // 拦截请求
}
return true; // 放行请求
}
}
RestTemplate 是 Spring 提供的一个用于发送 HTTP 请求的客户端工具类,支持 RESTful 风格的请求。在 Spring Boot 中,RestTemplate 可以通过自动配置(Auto-Configuration)快速集成到项目中,无需手动创建和管理实例。
Spring Boot 通过 RestTemplateAutoConfiguration
自动配置类,为项目提供默认的 RestTemplate
Bean。如果项目中引入了 spring-boot-starter-web
依赖,Spring Boot 会自动配置 RestTemplateBuilder
,用于构建 RestTemplate
实例。
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
RestTemplate
:@Autowired
private RestTemplate restTemplate;
如果需要自定义 RestTemplate
(如设置超时时间、拦截器等),可以通过 RestTemplateBuilder
配置:
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder
.setConnectTimeout(Duration.ofSeconds(5))
.setReadTimeout(Duration.ofSeconds(5))
.build();
}
spring-boot-starter-web
,自动配置不会生效。RestTemplate
Bean,可能会导致冲突。RestTemplate
默认会抛出异常,需结合 ResponseErrorHandler
处理错误响应。@RestController
public class DemoController {
@Autowired
private RestTemplate restTemplate;
@GetMapping("/call-api")
public String callExternalApi() {
String url = "https://api.example.com/data";
return restTemplate.getForObject(url, String.class);
}
}
RestTemplate
是线程安全的,可以全局共享一个实例。RestTemplate
实例,避免频繁创建。WebClient
(响应式编程替代方案)。GET 请求模板方法是一种封装了 HTTP GET 请求通用逻辑的代码模板,通常包含 URL 构造、参数拼接、请求发送和响应处理等步骤。通过模板方法可以避免重复编写基础代码,提高开发效率。
public static String sendGetRequest(String url, Map<String, String> params) throws IOException {
// 1. 构建带参数的URL
StringBuilder urlBuilder = new StringBuilder(url);
if (params != null && !params.isEmpty()) {
urlBuilder.append("?");
for (Map.Entry<String, String> entry : params.entrySet()) {
urlBuilder.append(URLEncoder.encode(entry.getKey(), "UTF-8"))
.append("=")
.append(URLEncoder.encode(entry.getValue(), "UTF-8"))
.append("&");
}
urlBuilder.deleteCharAt(urlBuilder.length() - 1); // 删除最后一个&
}
// 2. 创建连接
HttpURLConnection connection = (HttpURLConnection) new URL(urlBuilder.toString()).openConnection();
connection.setRequestMethod("GET");
// 3. 处理响应
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(connection.getInputStream()))) {
StringBuilder response = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
response.append(line);
}
return response.toString();
} finally {
connection.disconnect();
}
}
POST 请求模板方法是一种封装了 HTTP POST 请求核心逻辑的代码结构,通常包含请求构建、参数处理、连接管理和响应处理等通用步骤。通过模板方法可以避免重复编写底层 HTTP 通信代码。
public static String postTemplate(String url, String params) throws IOException {
URL obj = new URL(url);
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
// 基础配置
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
con.setConnectTimeout(5000);
con.setDoOutput(true);
// 发送请求体
try(OutputStream os = con.getOutputStream()) {
byte[] input = params.getBytes(StandardCharsets.UTF_8);
os.write(input, 0, input.length);
}
// 处理响应
try(BufferedReader br = new BufferedReader(
new InputStreamReader(con.getInputStream(), StandardCharsets.UTF_8))) {
StringBuilder response = new StringBuilder();
String responseLine;
while ((responseLine = br.readLine()) != null) {
response.append(responseLine.trim());
}
return response.toString();
}
}
public static String postJsonTemplate(String url, Object data) throws IOException {
HttpURLConnection con = (HttpURLConnection) new URL(url).openConnection();
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type", "application/json");
// 使用Jackson转换对象为JSON
ObjectMapper mapper = new ObjectMapper();
try(OutputStream os = con.getOutputStream()) {
mapper.writeValue(os, data);
}
// 处理非200响应
if (con.getResponseCode() != 200) {
throw new IOException("HTTP error: " + con.getResponseCode());
}
return new String(con.getInputStream().readAllBytes(), StandardCharsets.UTF_8);
}
请求/响应类型转换是指在HTTP请求和响应过程中,将数据从一种格式转换为另一种格式的过程。常见的转换包括:
// 使用Jackson将Java对象转为JSON字符串
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(user);
// 将JSON字符串转为Java对象
User user = mapper.readValue(json, User.class);
// 使用JAXB将Java对象转为XML
JAXBContext context = JAXBContext.newInstance(User.class);
Marshaller marshaller = context.createMarshaller();
StringWriter writer = new StringWriter();
marshaller.marshal(user, writer);
String xml = writer.toString();
// 将XML转为Java对象
Unmarshaller unmarshaller = context.createUnmarshaller();
User user = (User) unmarshaller.unmarshal(new StringReader(xml));
// Spring MVC自动将表单数据绑定到对象
@PostMapping("/users")
public String createUser(@ModelAttribute User user) {
// user对象已自动填充表单数据
}
@JsonProperty("user_name")
private String username;
@JsonFormat(pattern = "yyyy-MM-dd")
private Date birthDate;
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
异常统一处理是指在Java应用中,通过集中化的方式捕获和处理各种异常,避免在业务代码中分散处理异常逻辑。通常通过@ControllerAdvice
或@RestControllerAdvice
注解结合@ExceptionHandler
实现。
@RestControllerAdvice
public class GlobalExceptionHandler {
// 处理自定义业务异常
@ExceptionHandler(BusinessException.class)
public Result handleBusinessException(BusinessException e) {
log.error("业务异常: {}", e.getMessage());
return Result.fail(e.getCode(), e.getMessage());
}
// 处理系统异常
@ExceptionHandler(Exception.class)
public Result handleException(Exception e) {
log.error("系统异常: ", e);
return Result.fail(500, "系统繁忙,请稍后再试");
}
}
BusinessException
比Exception
优先)public class BusinessException extends RuntimeException {
private int code;
// 构造方法省略...
}
public enum ErrorCode {
PARAM_ERROR(1001, "参数错误"),
USER_NOT_FOUND(1002, "用户不存在");
// 其他字段和方法...
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public Result handleValidException(MethodArgumentNotValidException e) {
String message = e.getBindingResult().getFieldError().getDefaultMessage();
return Result.fail(400, message);
}
负载均衡集成是指在Java应用中,通过特定的技术手段将HTTP请求(如GET、POST)分发到多个服务器或服务实例上,以实现流量均衡、提高系统吞吐量和容错能力。
@RestController
public class ClientController {
@Autowired
private RestTemplate restTemplate;
@GetMapping("/balance")
public String getService() {
// 通过服务名调用,Ribbon自动负载均衡
return restTemplate.getForObject(
"http://service-provider/api/data",
String.class
);
}
}
http {
upstream backend {
server 192.168.1.1:8080;
server 192.168.1.2:8080;
}
server {
location / {
proxy_pass http://backend;
}
}
}
// 1. 添加依赖(Spring Cloud 2020+)
implementation 'org.springframework.cloud:spring-cloud-starter-loadbalancer'
// 2. 启用负载均衡的RestTemplate
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
// 3. 调用服务(自动负载均衡)
String result = restTemplate.getForObject(
"http://service-name/api/resource",
String.class
);
ReactorServiceInstanceLoadBalancer
接口。响应式编程是一种基于异步数据流的编程范式,核心思想是通过声明式代码处理异步事件和数据流。在Java中,响应式编程模型通常通过Reactive Streams
规范实现,主要库包括RxJava
、Project Reactor
等。
// 创建Flux流
Flux<String> flux = Flux.just("请求1", "请求2", "请求3")
.delayElements(Duration.ofMillis(500));
// 订阅处理
flux.subscribe(
data -> System.out.println("处理: " + data), // 正常处理
error -> System.err.println("错误: " + error), // 错误处理
() -> System.out.println("完成") // 完成回调
);
特性 | 响应式编程 | 传统编程 |
---|---|---|
线程模型 | 异步非阻塞 | 同步阻塞 |
资源使用 | 高效 | 相对低效 |
代码风格 | 声明式 | 命令式 |
错误处理 | 流式 | try-catch |
WebClient 是 Spring 5 引入的非阻塞、响应式 HTTP 客户端,用于发送 HTTP 请求并处理响应。它是 Spring WebFlux 的一部分,适用于异步、高性能的网络通信场景。
创建 WebClient 实例
// 方式1:通过工厂方法创建
WebClient client = WebClient.create();
// 方式2:通过 Builder 自定义配置
WebClient client = WebClient.builder()
.baseUrl("https://api.example.com")
.defaultHeader("Content-Type", "application/json")
.build();
发送请求
get()
/ post()
/ put()
/ delete()
:指定 HTTP 方法。uri()
:设置请求路径或完整 URL。retrieve()
:直接获取响应体。exchangeToMono()
/ exchangeToFlux()
:更灵活地处理响应(包括状态码、头信息等)。处理响应
bodyToMono()
:将响应体转换为 Mono(单个对象)。bodyToFlux()
:将响应体转换为 Flux(流式数据)。onStatus()
:自定义错误处理。GET 请求示例
WebClient client = WebClient.create("https://api.example.com");
Mono<String> response = client.get()
.uri("/users/{id}", 1)
.retrieve()
.bodyToMono(String.class);
response.subscribe(System.out::println); // 异步打印结果
POST 请求示例
Mono<String> response = client.post()
.uri("/users")
.contentType(MediaType.APPLICATION_JSON)
.bodyValue("{\"name\":\"John\"}")
.retrieve()
.bodyToMono(String.class);
Mono
/Flux
使用。HttpClient
配置。HttpClient
设置全局或单次请求超时。HttpClient httpClient = HttpClient.create()
.responseTimeout(Duration.ofSeconds(5));
WebClient client = WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(httpClient))
.build();
RestTemplate
(已标记为废弃)。GET 请求链式调用是一种通过方法连续调用的方式构建 HTTP GET 请求的技术。它通过返回对象自身(this
)实现方法的连续调用,从而简化请求参数的拼接和配置。
HttpClient
(Java 11+)HttpClient client = HttpClient.newHttpClient();
String url = HttpRequest.newBuilder()
.uri(URI.create("https://example.com/api"))
.GET()
.build()
.uri() // 获取 URI 对象
.toString();
public class GetRequestBuilder {
private String baseUrl;
private Map<String, String> params = new HashMap<>();
public GetRequestBuilder(String baseUrl) {
this.baseUrl = baseUrl;
}
public GetRequestBuilder addParam(String key, String value) {
params.put(key, value);
return this;
}
public String build() {
StringBuilder url = new StringBuilder(baseUrl);
if (!params.isEmpty()) {
url.append("?");
params.forEach((k, v) -> url.append(k).append("=").append(v).append("&"));
url.deleteCharAt(url.length() - 1); // 移除末尾的 &
}
return url.toString();
}
}
// 使用示例
String url = new GetRequestBuilder("https://example.com/api")
.addParam("page", "1")
.addParam("size", "10")
.build();
URLEncoder.encode
),避免特殊字符(如 &
, =
)破坏 URL 结构。null
或空字符串参数,避免生成无效 URL。addParam
)。POST 请求数据绑定是指将客户端通过 HTTP POST 方法提交的数据(如表单数据、JSON 等)自动映射到服务器端的 Java 对象或方法参数的过程。这是 Web 开发中处理用户输入的核心机制。
// 获取表单参数
String username = request.getParameter("username");
String password = request.getParameter("password");
@PostMapping("/register")
public String register(@ModelAttribute User user) {
// user 对象自动绑定表单数据
// 属性名需与表单字段名一致
}
@PostMapping("/api/users")
public ResponseEntity createUser(@RequestBody User user) {
// 自动将请求体中的JSON转换为User对象
// 需要Content-Type: application/json
}
字段名不一致:使用 @RequestParam
注解指定别名
@PostMapping("/login")
public String login(@RequestParam("u") String username) {...}
嵌套对象绑定:使用点号语法
<input name="address.city" value="Beijing">
日期格式化:使用 @DateTimeFormat
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date birthDate;
数据验证:结合 @Valid
进行校验
public String save(@Valid @ModelAttribute User user, BindingResult result)
响应结果订阅处理是指在发送 HTTP 请求(如 GET、POST)后,通过异步或回调的方式处理服务器返回的响应数据。这种方式常用于非阻塞式编程,避免线程阻塞,提升程序性能。
回调函数(Callback):
httpClient.get(url, new Callback() {
@Override
public void onSuccess(Response response) {
System.out.println("成功:" + response.body());
}
@Override
public void onFailure(Exception e) {
System.err.println("失败:" + e.getMessage());
}
});
Future/Promise:
CompletableFuture
(Java 8+)实现异步结果处理。CompletableFuture<Response> future = httpClient.getAsync(url);
future.thenAccept(response -> {
System.out.println("响应数据:" + response.body());
}).exceptionally(e -> {
System.err.println("请求异常:" + e.getMessage());
return null;
});
Reactive Streams(响应式编程):
httpClient.getObservable(url)
.subscribe(
response -> System.out.println("响应:" + response),
error -> System.err.println("错误:" + error)
);
Activity
引用)。以下是一个使用 HttpClient
(Java 11+)的异步 GET 请求示例:
import java.net.URI;
import java.net.http.*;
import java.util.concurrent.CompletableFuture;
public class AsyncHttpExample {
public static void main(String[] args) {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com/data"))
.build();
CompletableFuture<HttpResponse<String>> future =
client.sendAsync(request, HttpResponse.BodyHandlers.ofString());
future.thenApply(response -> {
System.out.println("状态码:" + response.statusCode());
return response.body();
}).thenAccept(body -> {
System.out.println("响应体:" + body);
}).exceptionally(e -> {
System.err.println("请求失败:" + e.getMessage());
return null;
});
// 防止主线程提前退出
future.join();
}
}
请求超时配置是指在发送HTTP请求时,设置一个时间限制。如果在该时间内未收到服务器的响应,则自动终止请求并抛出超时异常。这是网络编程中保证系统健壮性的重要机制。
URL url = new URL("http://example.com");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setConnectTimeout(5000); // 连接超时5秒
connection.setReadTimeout(10000); // 读取超时10秒
RequestConfig config = RequestConfig.custom()
.setConnectTimeout(5000) // 连接超时
.setSocketTimeout(10000) // 数据传输超时
.build();
CloseableHttpClient client = HttpClientBuilder.create()
.setDefaultRequestConfig(config)
.build();
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(5, TimeUnit.SECONDS) // 连接超时
.readTimeout(10, TimeUnit.SECONDS) // 读取超时
.writeTimeout(10, TimeUnit.SECONDS) // 写入超时
.build();
参数签名验证是一种确保请求数据完整性和来源可信的安全机制。通过将请求参数按特定规则排序后,使用密钥生成签名(通常为MD5、SHA1或HMAC等算法),服务端收到请求后以相同方式计算签名并进行比对,验证请求是否被篡改。
客户端:
sign
)key1=value1&key2=value2
格式// 示例:MD5签名生成
public static String generateSign(Map<String, String> params, String secret) {
params.remove("sign"); // 排除签名字段
StringJoiner sj = new StringJoiner("&");
params.entrySet().stream()
.sorted(Map.Entry.comparingByKey())
.forEach(e -> sj.add(e.getKey() + "=" + e.getValue()));
sj.add("key=" + secret);
return DigestUtils.md5Hex(sj.toString());
}
服务端:
// 错误示例:未排序直接拼接
String raw = params.entrySet().stream()
.map(e -> e.getKey()+"="+e.getValue())
.collect(Collectors.joining("&"));
// 会导致与服务端计算不一致
通过规范的签名验证,可有效防御约70%的常见API攻击行为。
HTTPS 证书(SSL/TLS 证书)是用于验证服务器身份并加密客户端与服务器之间通信的数字证书。它由受信任的证书颁发机构(CA)签发,确保数据传输的安全性。
import javax.net.ssl.*;
import java.security.cert.X509Certificate;
public class SSLUtil {
public static void disableCertificateValidation() {
try {
// 创建信任所有证书的 TrustManager
TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {}
public void checkServerTrusted(X509Certificate[] certs, String authType) {}
}
};
// 应用自定义 TrustManager
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
// 忽略主机名验证
HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> true);
} catch (Exception e) {
e.printStackTrace();
}
}
}
import java.io.FileInputStream;
import java.security.KeyStore;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
public class SSLUtil {
public static SSLContext loadCustomCertificate(String certPath, String password) throws Exception {
// 加载证书文件
KeyStore keyStore = KeyStore.getInstance("PKCS12");
try (FileInputStream fis = new FileInputStream(certPath)) {
keyStore.load(fis, password.toCharArray());
}
// 初始化 TrustManagerFactory
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(keyStore);
// 创建 SSLContext
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);
return sslContext;
}
}
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.ssl.SSLContexts;
public class HttpsClientExample {
public static void main(String[] args) throws Exception {
// 加载自定义证书(可选)
SSLContext sslContext = SSLUtil.loadCustomCertificate("path/to/cert.p12", "password");
// 创建 HttpClient
try (CloseableHttpClient httpClient = HttpClients.custom()
.setSSLContext(sslContext)
.build()) {
// 发送 HTTPS 请求
HttpGet httpGet = new HttpGet("https://example.com/api");
httpClient.execute(httpGet, response -> {
System.out.println("Response Code: " + response.getStatusLine().getStatusCode());
return null;
});
}
}
}
代理服务器(Proxy Server)是客户端和目标服务器之间的中间服务器,用于转发请求和响应。在Java中配置代理服务器可以让应用程序通过代理访问网络资源。
System.setProperty("http.proxyHost", "proxy.example.com");
System.setProperty("http.proxyPort", "8080");
// 对于HTTPS
System.setProperty("https.proxyHost", "proxy.example.com");
System.setProperty("https.proxyPort", "8080");
Proxy proxy = new Proxy(Proxy.Type.HTTP,
new InetSocketAddress("proxy.example.com", 8080));
URL url = new URL("http://target.example.com");
HttpURLConnection conn = (HttpURLConnection) url.openConnection(proxy);
Authenticator.setDefault(new Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("username", "password".toCharArray());
}
});
// 设置代理
System.setProperty("http.proxyHost", "192.168.1.100");
System.setProperty("http.proxyPort", "3128");
// 执行HTTP请求
URL url = new URL("http://example.com/api");
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("GET");
// 读取响应
try(BufferedReader in = new BufferedReader(
new InputStreamReader(con.getInputStream()))) {
String inputLine;
StringBuilder content = new StringBuilder();
while ((inputLine = in.readLine()) != null) {
content.append(inputLine);
}
System.out.println(content.toString());
}
对于更复杂的场景(如SOCKS代理、动态代理切换),可以考虑使用:
连接超时重试是指在网络请求(如 GET、POST)因连接超时失败后,自动或手动重新发起请求的机制。超时通常由网络延迟、服务器负载过高或防火墙限制等原因引起。重试策略可提高请求成功率,尤其在弱网络环境下。
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
public class RetryExample {
private static final int MAX_RETRIES = 3;
private static final long BASE_DELAY_MS = 1000; // 初始延迟 1s
public static String sendGetWithRetry(String url) throws IOException, InterruptedException {
int retryCount = 0;
IOException lastException = null;
while (retryCount < MAX_RETRIES) {
try {
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000); // 连接超时 5s
conn.setReadTimeout(5000); // 读取超时 5s
int responseCode = conn.getResponseCode();
if (responseCode == 200) {
return "Request succeeded after " + retryCount + " retries";
}
} catch (IOException e) {
lastException = e;
retryCount++;
if (retryCount < MAX_RETRIES) {
long delay = BASE_DELAY_MS * (1 << (retryCount - 1)); // 指数退避
Thread.sleep(delay);
}
}
}
throw lastException; // 重试耗尽后抛出最后一次异常
}
public static void main(String[] args) {
try {
String result = sendGetWithRetry("https://example.com/api");
System.out.println(result);
} catch (Exception e) {
e.printStackTrace();
}
}
}
文件下载进度监控是指在通过网络下载文件时,实时跟踪和显示下载进度的技术。通常以百分比或已下载字节数/总字节数的形式展示,提升用户体验。
URL url = new URL("http://example.com/file.zip");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// 获取文件总大小
long fileSize = conn.getContentLengthLong();
try (InputStream is = conn.getInputStream();
FileOutputStream fos = new FileOutputStream("local.zip")) {
byte[] buffer = new byte[4096];
long downloaded = 0;
int read;
while ((read = is.read(buffer)) != -1) {
fos.write(buffer, 0, read);
downloaded += read;
// 计算并显示进度
double progress = (double) downloaded / fileSize * 100;
System.out.printf("下载进度: %.2f%%\n", progress);
}
}
CloseableHttpClient client = HttpClients.createDefault();
HttpGet request = new HttpGet("http://example.com/file.zip");
try (CloseableHttpResponse response = client.execute(request);
InputStream is = response.getEntity().getContent()) {
long fileSize = response.getEntity().getContentLength();
long downloaded = 0;
byte[] buffer = new byte[4096];
int read;
while ((read = is.read(buffer)) != -1) {
downloaded += read;
double progress = (double) downloaded / fileSize * 100;
System.out.printf("进度: %.2f%%\n", progress);
}
}
第三方 API 对接规范是指在调用外部服务提供的 API 时,需要遵循的一系列技术约定和流程标准。这些规范通常包括接口协议、认证方式、数据格式、错误处理、限流策略等,确保双方系统能稳定、安全地交互。
GET
/POST
/PUT
/DELETE
等方法。/users/{id}
)。snake_case
或 camelCase
)。Content-Type
(如 application/json
)、Authorization
等。200
成功,400
参数错误,500
服务异常)。code
和 message
字段。X-RateLimit-Limit
头标识每秒请求数上限。429 Too Many Requests
。/v1/users
)或请求头(如 Accept-Version: v1
)区分。5xx
)实时通知。// 使用 HttpClient 调用第三方 API(GET 请求)
public String callThirdPartyAPI(String apiUrl, String apiKey) throws IOException {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(apiUrl))
.header("Authorization", "Bearer " + apiKey)
.header("Content-Type", "application/json")
.GET()
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() == 200) {
return response.body();
} else {
throw new RuntimeException("API 调用失败: " + response.statusCode());
}
}