HTTP请求方法全面解析:从基础到面试实战

HTTP请求方法全面解析:从基础到面试实战

一、HTTP请求方法深度剖析

1. HTTP请求方法概述

HTTP请求方法是客户端告诉服务器期望执行什么操作的指令。它们在RESTful架构设计中扮演着关键角色,决定了API的行为模式和资源操作方式。

HTTP协议的演进

2. 八大核心HTTP方法详述

① GET - 获取资源

核心特征

  • ✅ 安全的(Safe):不修改服务器状态
  • 🔄 幂等的(Idempotent):重复请求效果一致
  • 💾 可缓存的(Cacheable)

请求结构

http 复制代码
GET /api/products/123 HTTP/1.1
Host: api.example.com
Accept: application/json
User-Agent: Mozilla/5.0
Cache-Control: no-cache

Java实现示例

java 复制代码
public class GetRequestExample {

// 使用HttpURLConnection实现GET请求
public static String httpGet(String urlStr) throws IOException {
URL url = new URL(urlStr);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);
conn.setReadTimeout(10000);

int responseCode = conn.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
try (BufferedReader in = new BufferedReader(
new InputStreamReader(conn.getInputStream()))) {
StringBuilder response = new StringBuilder();
String line;
while ((line = in.readLine()) != null) {
response.append(line);
}
}
return response.toString();
}
} else {
throw new IOException("HTTP error: " + responseCode);
}
}

// 使用OkHttp实现GET请求
public static String okHttpGet(String urlStr) throws IOException {
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(Duration.ofSeconds(5))
.readTimeout(Duration.ofSeconds(10))
.build();

Request request = new Request.Builder()
.url(urlStr)
.addHeader("Accept", "application/json")
.build();

try (Response response = client.newCall(request).execute()) {
if (response.isSuccessful()) {
{
return response.body().string();
} else {
throw new IOException("HTTP error: " + response.code());
}
}

public static void main(String[] args) {
try {
String response = httpGet("https://jsonplaceholder.typicode.com/todos/1");
System.out.println("GET Response: " + response);
} catch (IOException e) {
e.printStackTrace();
}
}
}
② POST - 创建资源

核心特征

  • ❌ 不安全(Non-Safe):会修改服务器状态
  • ❌ 非幂等(Non-Idempotent):重复请求可能有不同结果
  • ⚠️ 有条件缓存

完整商业级POST实现

java 复制代码
public class PostRequestExample {

// 通用的JSON POST请求
public static String sendJsonPost(String urlStr, String jsonPayload) throws IOException {
URL url = new URL(urlStr);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json");
conn.setRequestProperty("Accept", "application/json");
conn.setDoOutput(true);

// 写入请求体
try (OutputStream os = conn.getOutputStream()) {
byte[] input = jsonPayload.getBytes(StandardCharsets.UTF_8);
os.write(input, 0, input.length);
}

// 读取响应
int responseCode = conn.getResponseCode();
if (responseCode >= 200 && responseCode < 300) {
try (BufferedReader br = new BufferedReader(
new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8))) {
StringBuilder response = new StringBuilder();
String responseLine;
while ((responseLine = br.readLine()) != null) {
response.append(responseLine.trim());
}
return response.toString();
}
} else {
// 处理错误情况
try (BufferedReader br = new BufferedReader new BufferedReader(
new InputStreamReader(conn.getErrorStream(), StandardCharsets.UTF_8))) {
{
StringBuilder errorResponse = new StringBuilder();
String errorLine;
while ((errorLine = br.readLine()) != null) {
errorResponse.append(errorLine.trim());
}
throw new IOException("HTTP Error: " + responseCode + ", Message: " + errorResponse);
}
}
}

// 带认证头的POST请求
public static String sendAuthenticatedPost(String urlStr, String payload, String token) throws IOException {
URL url = new URL(urlStr);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json");
conn.setRequestProperty("Authorization", "Bearer " + token);
conn.setDoOutput(true);

// 写入请求体
try (OutputStream os = conn.getOutputStream()) {
byte[] input = payload.getBytes(StandardCharsets.UTF_8);
os.write(input, 0, input.length);
}

// 读取响应...
return readResponse(conn);
}

// 电商下单接口实战示例
public static String placeOrder(String userId, List<CartItem> items, PaymentInfo paymentInfo) throws IOException {
ObjectMapper mapper = new ObjectMapper();

OrderRequest orderRequest = new OrderRequest(userId, items, paymentInfo);
String jsonPayload = mapper.writeValueAsString(orderRequest);

return sendJsonPost("https://api.ecommerce.com/v1/orders", jsonPayload);
}
}

// 订单请求DTO
class OrderRequest {
private String userId;
private List<CartItem> items;
private PaymentInfo paymentInfo;
private String idempotencyKey; // 防止重复下单

public OrderRequest(String userId, List<CartItem> items, PaymentInfo paymentInfo) {
this.userId = userId;
this.items = items;
this.paymentInfo = paymentInfo;
this.idempotencyKey = UUID.randomUUID().toString());

// getters and setters
}
③ PUT vs PATCH - 更新操作深度辨析
关键技术差异对比:
方面 PUT PATCH
更新范围 整个资源 部分字段
幂等性 必须保证 推荐保证
带宽使用 较高(传送完整资源) 较低(只传变更字段)
错误恢复 重新发送整个资源 只需发送变更字段
冲突解决 乐观锁控制 细粒度锁定

Java实现对比

java 复制代码
public class UpdateOperations {

// PUT - 完全替换用户信息
public static String putUpdateUser(Long userId, User user) throws IOException {
ObjectMapper mapper = new ObjectMapper();
String jsonPayload = mapper.writeValueAsString(user);

URL url = new URL("https://api.example.com/users/" + userId);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("PUT");
conn.setRequestProperty("Content-Type", "application/json");
conn.setRequestProperty("If-Match", user.getEtag()); // 乐观锁控制

return sendJsonRequest(conn, jsonPayload);
}

// PATCH - 部分更新用户邮箱
public static String patchUpdateEmail(Long userId, String newEmail) throws IOException throws IOException {
// JSON Patch格式
String jsonPatch = "[{ \"op\": \"replace\", \"path\": \"/email\", \"value\": \"" + newEmail + "\" }]";

URL url = new URL("https://api.example.com/users/" + userId);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("PATCH");
conn.setRequestProperty("Content-Type", "application/json-patch+json");

return sendJsonRequest(conn, jsonPatch);
}

// 企业级PUT实现
public static String enterprisePut(String urlStr, Object entity, Map<String, String> headers) throws IOException {
ObjectMapper mapper = new ObjectMapper();
String jsonPayload = mapper.writeValueAsString(entity);

URL url = new URL(urlStr);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("PUT");

// 设置自定义头
if (headers != null) {
for (Map.Entry<String, String> entry : headers.entrySet()) {
{
conn.setRequestProperty(entry.getKey(), entry.getValue());
}

conn.setDoOutput(true);
writePayload(conn, jsonPayload);

return handleResponse(conn);
}

// 幂等性保障机制
public static String idempotentPut(String urlStr, Object entity, String idempotencyKey) throws IOException {
ObjectMapper mapper = new ObjectMapper();
String jsonPayload = mapper.writeValueAsString(entity);

URL url = new URL(urlStr);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("PUT");
conn.setRequestProperty("Content-Type", "application/json");
conn.setRequestProperty("Idempotency-Key", idempotencyKey);

return sendJsonRequest(conn, jsonPayload);
}
}
④ DELETE - 资源删除
java 复制代码
public class DeleteExamples {

// 硬删除 - 直接从数据库中删除
public static String hardDelete(String urlStr) throws IOException throws IOException {
URL url = new URL(urlStr);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("DELETE");

int responseCode = conn.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_NO_CONTENT) {
return "Successfully deleted";
} else {
throw new IOException("Delete failed: " + responseCode);
}
}

// 软删除 - 标记删除状态
public static String softDelete(String urlStr) throws IOException {
String deletePatch = "[{ \"op\": \"replace\", \"path\": \"/deleted\", \"value\": true }]";

URL url = new URL(urlStr);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("PATCH");
conn.setRequestProperty("Content-Type", "application/json-patch+json");

return sendJsonRequest(conn, deletePatch);
}

// 批量删除
public static String batchDelete(List<Long> ids) throws IOException {
BatchDeleteRequest batchRequest = new BatchDeleteRequest(ids);
ObjectMapper mapper = new ObjectMapper();
String jsonPayload = mapper.writeValueAsString(batchRequest);

return sendJsonPost("https://api.example.com/bulk-delete", jsonPayload);
}
}

三、HTTP方法特性全方位对比

核心技术指标矩阵

HTTP方法 安全性 幂等性 缓存性 请求体 成功状态码 典型用例
GET ✅ 安全 ✅ 幂等 ✅ 可缓存 ❌ 无 200, 304 商品浏览、搜索
POST ❌ 不安全 ❌ 非幂等 ⚠️ 有条件 ✅ 有 201, 200 用户注册、订单提交
PUT ❌ 不安全 ✅ 幂等 ❌ 不可缓存 ✅ 有 200, 204 个人资料全量更新
DELETE ❌ 不安全 ✅ 幂等 ❌ 不可缓存 ❌ 无 204, 200 删除订单、注销账号
PATCH ❌ 不安全 ⚠️ 应设计为幂等 ❌ 不可缓存 ✅ 有 200 修改邮箱、局部更新

真实场景应用指南

java 复制代码
public class HttpMethodSelectorGuide {

/**
* CRUD操作与方法对应关系
*/
public enum Operation {
CREATE(POST),
READ(GET),
UPDATE_FULL(PUT),
UPDATE_PARTIAL(PATCH),
DELETE(DELETE);

private final String method;

Operation(String method) {
this.method = method;
}

public String getMethod() {
return method;
}
}

/**
* 根据操作意图选择最合适的HTTP方法
*/
public static String selectBestMethod(ActionContext context) {
switch (context.getIntent()) {
case RETRIEVE_INFO:
return "GET";
case CREATE_NEW_RESOURCE:
return "POST";
case REPLACE_COMPLETELY:
return "PUT";
case MODIFY_PARTIALLY:
return "PATCH";
case REMOVE_RESOURCE:
return "DELETE";
default:
throw new IllegalArgumentException("Unknown intent: " + context.getIntent());
}
}
}

四、Java高级HTTP客户端实战

1. Spring RestTemplate综合应用

java 复制代码
@Service
public class ApiClientService {

private final RestTemplate restTemplate;

public ApiClientService(RestTemplateBuilder builder) {
this.restTemplate = builder
.setConnectTimeout(Duration.ofSeconds(10))
.setReadTimeout(Duration.ofMinutes(1))
.additionalInterceptors(new LoggingInterceptor()))
.build();
}

// RESTful API完整CRUD操作
public class UserApiClient {

// CREATE - 注册用户
public User register(UserRegistrationDto registrationDto) {
HttpHeaders headers = new HttpHeaders();
headersheaders.setContentType(MediaType.APPLICATION_JSON);

HttpEntity<UserRegistrationDto> request = new HttpEntity<>(registrationDto, headers);

ResponseEntity<User> response = restTemplate.postForEntity(
BASE_URL + "/users", request, User.class);

if (response.getStatusCode() == HttpStatus.CREATED) {
return response.getBody();
} else {
throw new ApiException("Registration failed");
}
}

// READ - 获取用户详情
public User getUserById(Long id) {
ResponseEntity<User> response = restTemplate.getForEntity(
BASE_URL + "/users/" + id, User.class);

return response.getBody();
}

// UPDATE FULL - 修改整个用户对象
public User updateUserFull(Long id, User user) {
HttpHeaders headers = new HttpHeaders();
headers.setIfMatch(user.getEtag()); // 乐观锁

HttpEntity<User> request = new HttpEntity<>(user, headers);

ResponseEntity<User> response = restTemplate.exchange(
BASE_URL + "/users/" + id, HttpMethod.PUT, request, User.class);

return response.getBody();
}

// UPDATE PARTIAL - 只修改密码
public User changePassword(Long id, PasswordChangeDto passwordChange) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.valueOf("application/json-patch+json")));

// JSON Patch格式
JsonPatch patch = JsonPatch.fromJson(objectMapper.readTree(
"["[{ \"op\": \"replace\", \"path\": \"/password\", \"value\": \"" + passwordChange.getNewPassword() + "\" }]"));

HttpEntity<JsonPatch> request = new HttpEntity<>(patch, headers);

ResponseEntity<User> response = restTemplate.exchange(
BASE_URL + "/users/" + id, HttpMethod.PATCH, request, User.class);

return response.getBody();
}

// DELETE - 注销账户
public void deleteAccount(Long id) {
HttpHeaders headers = new HttpHeaders();
headers.setBasicAuth(getCurrentUsername(), getCurrentPassword()));

restTemplate.delete(BASE_URL + "/users/" + id);
}
}
}

2. Apache HttpClient企业级配置

java 复制代码
@Component
public class EnterpriseHttpClient {

private final CloseableHttpClient httpClient;

public EnterpriseHttpClient() {
// 连接池配置
PoolingHttpClientConnectionManager connectionManager =
new PoolingHttpClientConnectionManager();
connectionManager.setMaxTotal(200); // 总连接数
connectionManager.setDefaultMaxPerRoute(50); // 每路由连接数

// 请求配置
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(15000)
.setSocketTimeout(60000)
.setConnectionRequestTimeout(15000)
.build();

this.httpClient = HttpClients.custom()
.setConnectionManager(connectionManager)
.setDefaultRequestConfig(requestConfig)
.addInterceptorLast(new RetryInterceptor())
.addInterceptorLast(new MetricsInterceptor())
.build();
}

// 带有重试机制的GET请求
public String robustHttpGet(String urlStr, int maxRetries) throws IOException {
int retryCount = 0;

while (retryCount <= maxRetries) {
try {
HttpGet request = new HttpGet(urlStr);
request.setHeader("Accept", "application/json");

try (CloseableHttpResponse response = httpClient.execute(request)) {
int statusCode = response.getStatusLine().getStatusCode();

();

if (statusCode >= 200 && statusCode < 400) {
return EntityUtils.toString(response.getEntity());
} else if (shouldRetry(statusCode)) {
retryCount++;
Thread.sleep(exponentialBackoff(retryCount)); // 指数退避
} else {
{
throw new IOException("HTTP Error: " + statusCode);
}
} catch (ConnectTimeoutException | SocketTimeoutException e) {
retryCount++;
if (retryCount > maxRetries) {
throw e;
}
}
}

// 断路器模式的POST请求
public String circuitBreakerPost(String urlStr, String payload) throws IOException {
CircuitBreaker breaker = circuitBreakerRegistry.circuitBreaker("api-service"));

return breaker.executeSupplier(() -> {
try {
return executePost(urlStr, payload);
} catch (IOException ex) {
throw new RuntimeException(ex);
}
});
}
}
}

五、HTTP面试高频真题深度解析

🎯 Part 1:基础概念题

题目1:GET和POST的本质区别是什么?

参考答案

java 复制代码
/**
* GET vs POST核心区别深度解析
*/
public class GetVsPostComparison {

/*
* 根本区别:语义层面
* GET: 获取资源(Safe & Idempotent)
* POST: 提交数据处理(Non-Safe & Non-Idempotent)
*/

// 1. 数据传输方式
class TransmissionDifference {
// GET - 参数放在URL中
String getUrl = "https://api.com/search?keyword=mobile&limit=10");

// POST - 参数放在请求体中
String postUrl = "https://api.com/users";
String postBody = "{ \"name\": \"John\", \"age\": 30 }";
}

// 2. 安全性差异
class SafetyConsiderations {
/*
* GET请求:
* - 参数暴露在URL中
* - 可能被浏览器历史记录
* - 可能被服务器日志记录
* => 不适合传输敏感信息
*/

/*
* POST请求:
* - 参数在请求体中
* - 相对安全(但仍需HTTPS加密)
*/
}

// 3. 幂等性影响
class IdempotenceImpact {
/*
* 前端需要考虑的重点:
* - GET请求可以直接刷新页面
* - POST请求刷新时会提示重新提交
*/
}
}

加分回答

java 复制代码
// 从HTTP协议规范角度深入解释
public class ProtocolLevelDifferences {

/*
* RFC 7231明确规定了各自的语义:
* GET: 安全的、幂等的,不应产生副作用
* POST: 不安全的、非幂等的,允许产生副作用
*/
}
题目2:PUT和POST都可以创建资源,它们有什么区别?

标准答案结构

java 复制代码
public class PutPostCreationDiff {

// 主要区别体现在客户端对资源标识的控制权上

/**
* 创建资源时的关键决策因素:
* - 谁来决定资源的ID?
* - 是否需要保证幂等性?
*/

enum CreationScenario {
// 当客户端不知道也不关心资源ID时 - 使用POST
CLIENT_CANT_DETERMINE_ID("POST"),

// 当客户端知道要创建的资源的完整标识时 - 使用PUT
RESOURCE_ID_DETERMINED_BY_CLIENT("PUT");
}

// 实例演示
public void demonstrateUsage() {
// POST创建 - ID由服务器生成
createWithPost("/articles", articleDto); // 返回 /articles/123

// PUT创建 - ID由客户端指定
createWithPut("/articles/123", articleDto); // 创建ID为123的文章
}
}

🎯 Part 2:进阶应用题

题目3:如何设计一个防重复提交的订单接口?

解决方案

java 复制代码
@Component
public class IdempotentOrderService {

private final RedisTemplate redisTemplate;

/**
* 幂等性保障三重机制:
*/

// 机制1:客户端生成的幂等键
public ResponseEntity<Order> createOrder(@RequestBody OrderRequest request,
@RequestHeader("Idempotency-Key") String idempotencyKey) {

// 第一步:检查幂等键
if (redisTemplate.hasKey(idempotencyKey)) {
// 已经处理过该请求
Order cachedOrder = (Order) redisTemplate.opsForValue().get(idempotencyKey)) {
return ResponseEntity.ok(cachedOrder);
}

// 第二步:执行业务逻辑
Order order = processOrderCreation(request);

// 第三步:存储幂等键与结果的映射
redisTemplate.opsForValue().set(idempotencyKey, order, Duration.ofHours(24)));

return ResponseEntity.created(URI.create("/orders/" + order.getId())).body(order);
}

// 机制2:数据库唯一约束
@Transactional
public synchronized public synchronized Order createOrderAtomic(OrderRequest request) {
// 依赖数据库的唯一约束来防止重复
}
}
}

🎯 Part 3:场景设计题

题目4:如何选择合适的HTTP方法来更新用户的邮件地址?

决策流程图

java 复制代码
public class MethodSelectionStrategy {

public String selectUpdateMethod(UpdateContext context) {
if (context.hasFullResource())) {
return "PUT"; // 完全替换
} else if (context.supportPartialUpdates())) {
{
return "PATCH"; // 推荐使用,避免误覆盖其他字段
} else {
{
return "POST"; // 通用更新端点
}
}
}
}

六、HTTP最佳实践与反模式

✅ 最佳实践清单

java 复制代码
public class HttpBestPractices {

// 1. 正确的状态码使用
class StatusCodes {
/*
* 200 OK - 一般成功响应
* 201 Created - 创建资源成功
* 204 No Content - 删除成功
* 400 Bad Request - 客户端错误
* 401 Unauthorized - 身份认证失败
* 403 Forbidden - 权限不足
* 404 Not Found - 资源不存在
* 409 Conflict - 资源冲突
* 422 Unprocessable Entity - 语义错误
*/
}

// 2. 正确的幂等性设计
public class IdempotenceDesignPatterns {

// 模式A:唯一交易号
public Order createOrder(String tradeNo, OrderRequest request) {
// 优先检查tradeNo是否已存在
}
}
}

// 3. 适当的缓存策略
public class CacheStrategies {

// GET请求适当设置缓存头
public ResponseEntity<?> cacheOptimization() {
return ResponseEntity.ok()
.cacheControl(CacheControl.maxAge(30, TimeUnit.DAYS)))
.eTag(generateStrongEtag())
.lastModified(lastModifiedTime))
))
.body(result);
}
}
}

❌ 常见反模式警告

java 复制代码
public class AntiPatternWarnings {

// 反模式1:使用GET执行有副作用的操作
@Deprecated
public void wrongApproach() {
// ❌ 错误的做法 - 用GET删除资源
doGet("/delete-user?id=123");

// ✅ 正确的做法 - 用DELETE方法
doDelete("/users/123");
}
}

七、性能优化与企业级考虑

高性能HTTP客户端配置

yaml 复制代码
# application.yml - Spring Boot HTTP客户端配置
spring:
web:
client:
timeout:
connect: 10000
read: 30000

http:
client:
pool:
max-total: 200
default-max-per-route: 20

resilience4j:
circuitbreaker:
instances:
apiclient:
failure-rate-threshold: 50
wait-duration-in-open-state: 60s

总结要点

通过对HTTP请求方法的深入学习,我们应该掌握:

  1. 核心方法论:深刻理解各方法的语义特性和适用范围
  2. 实用工具箱:熟练运用各类HTTP客户端完成不同的业务需求
  3. 面试准备:能够从容应对各种深度的HTTP相关问题
  4. 工程思维:在设计API时合理选择HTTP方法,充分考虑性能和用户体验

这份全面的HTTP请求方法指南不仅涵盖了理论基础,还包含了大量的实战代码和企业级最佳实践,帮助你在日常开发和求职面试中都游刃有余。

相关推荐
二宝1521 小时前
黑马商城day10-Redis面试篇
数据库·redis·面试
南部余额1 小时前
深入理解 SpringBoot 核心:自动配置原理、ImportSelector与配置加载机制
java·spring boot·自动配置原理·importselector
zhixingheyi_tian1 小时前
TestDFSIO 之 热点分析
android·java·javascript
步步为营DotNet1 小时前
深入解读CancellationToken:.NET异步操作的精准控制
java·前端·.net
无奈何杨1 小时前
业务接入风控决策,挑战验证与结果同步
后端
曹牧1 小时前
Java中使用List传入Oracle的IN查询
java·oracle·list
青衫码上行1 小时前
【JavaWeb学习 | 第17篇】JSP内置对象
java·开发语言·前端·学习·jsp
core5121 小时前
实战:用 Spring Boot 搭建 Model Context Protocol (MCP) 服务
java·spring boot·后端·model·模型·mcp
Arva .1 小时前
谈谈 HTTP 的缓存机制,服务器如何判断缓存是否过期?
服务器·http·缓存