news 2026/6/10 8:02:23

接口调用的代码实现:从入门到实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
接口调用的代码实现:从入门到实战

接口调用是现代软件开发中最基础、最核心的技能之一。本文将从最基础的 HTTP 请求讲起,逐步深入到生产级的接口调用方案,涵盖多种技术栈和实际场景。


一、基础篇:HTTP 请求的核心原理

1.1 HTTP 请求的本质

一个完整的 HTTP 请求包含以下要素:

plain

请求行: GET /api/users/1 HTTP/1.1 请求头: Host: api.example.com Content-Type: application/json Authorization: Bearer xxx 请求体: {"name": "Alice"} (GET请求通常无请求体)

1.2 最基础的接口调用(原生 Java)

import java.net.HttpURLConnection; import java.net.URL; import java.io.*; public class BasicHttpClient { public String sendGet(String urlString) throws Exception { URL url = new URL(urlString); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); conn.setConnectTimeout(5000); // 连接超时 conn.setReadTimeout(5000); // 读取超时 int responseCode = conn.getResponseCode(); System.out.println("Response Code: " + responseCode); BufferedReader reader = new BufferedReader( new InputStreamReader(conn.getInputStream()) ); StringBuilder response = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { response.append(line); } reader.close(); return response.toString(); } public String sendPost(String urlString, String jsonBody) throws Exception { URL url = new URL(urlString); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("POST"); conn.setRequestProperty("Content-Type", "application/json"); conn.setDoOutput(true); // 允许写入请求体 // 发送请求体 try (OutputStream os = conn.getOutputStream()) { byte[] input = jsonBody.getBytes("utf-8"); os.write(input, 0, input.length); } BufferedReader reader = new BufferedReader( new InputStreamReader(conn.getInputStream(), "utf-8") ); StringBuilder response = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { response.append(line.trim()); } return response.toString(); } }

注意:原生HttpURLConnection虽然零依赖,但代码冗长、功能有限,生产环境建议使用成熟的 HTTP 客户端库。


二、进阶篇:使用成熟 HTTP 客户端

2.1 Apache HttpClient(Java 经典方案)

Maven 依赖:

<dependency> <groupId>org.apache.httpcomponents.client5</groupId> <artifactId>httpclient5</artifactId> <version>5.3.1</version> </dependency>

封装工具类:

import org.apache.hc.client5.http.classic.methods.HttpGet; import org.apache.hc.client5.http.classic.methods.HttpPost; import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; import org.apache.hc.client5.http.impl.classic.HttpClients; import org.apache.hc.core5.http.io.entity.EntityUtils; import org.apache.hc.core5.http.io.entity.StringEntity; public class ApacheHttpClientUtil { private static final CloseableHttpClient httpClient = HttpClients.custom() .setMaxConnTotal(200) // 最大连接数 .setMaxConnPerRoute(50) // 每个路由最大连接数 .build(); /** * GET 请求 */ public static String doGet(String url) { HttpGet httpGet = new HttpGet(url); httpGet.addHeader("Accept", "application/json"); try (CloseableHttpResponse response = httpClient.execute(httpGet)) { return EntityUtils.toString(response.getEntity()); } catch (Exception e) { throw new RuntimeException("GET请求失败: " + url, e); } } /** * POST 请求(JSON) */ public static String doPost(String url, String jsonBody) { HttpPost httpPost = new HttpPost(url); httpPost.addHeader("Content-Type", "application/json"); httpPost.setEntity(new StringEntity(jsonBody)); try (CloseableHttpResponse response = httpClient.execute(httpPost)) { return EntityUtils.toString(response.getEntity()); } catch (Exception e) { throw new RuntimeException("POST请求失败: " + url, e); } } }

2.2 OkHttp(轻量高效,Android 首选)

Maven 依赖:

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

同步调用示例:

java

import okhttp3.*; import java.io.IOException; public class OkHttpDemo { private static final OkHttpClient client = new OkHttpClient.Builder() .connectTimeout(10, TimeUnit.SECONDS) .readTimeout(30, TimeUnit.SECONDS) .connectionPool(new ConnectionPool(10, 5, TimeUnit.MINUTES)) .build(); private static final MediaType JSON = MediaType.get("application/json; charset=utf-8"); // GET 请求 public String get(String url) throws IOException { Request request = new Request.Builder() .url(url) .header("User-Agent", "MyApp/1.0") .build(); try (Response response = client.newCall(request).execute()) { if (!response.isSuccessful()) { throw new IOException("Unexpected code: " + response); } return response.body().string(); } } // POST 请求 public String post(String url, String json) throws IOException { RequestBody body = RequestBody.create(json, JSON); Request request = new Request.Builder() .url(url) .post(body) .build(); try (Response response = client.newCall(request).execute()) { return response.body().string(); } } }

异步调用示例(非阻塞):

// 异步 GET,不阻塞主线程 client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { e.printStackTrace(); } @Override public void onResponse(Call call, Response response) throws IOException { try (ResponseBody responseBody = response.body()) { System.out.println(responseBody.string()); } } });

三、实战篇:Spring 生态中的接口调用

3.1 RestTemplate(Spring 经典方案)

import org.springframework.web.client.RestTemplate; import org.springframework.http.*; @Configuration public class RestTemplateConfig { @Bean public RestTemplate restTemplate() { SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory(); factory.setConnectTimeout(5000); factory.setReadTimeout(10000); return new RestTemplate(factory); } } @Service public class UserService { @Autowired private RestTemplate restTemplate; public User getUserById(Long id) { String url = "https://api.example.com/users/{id}"; // 路径参数 + 返回值自动映射 return restTemplate.getForObject(url, User.class, id); } public User createUser(User user) { String url = "https://api.example.com/users"; HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); HttpEntity<User> request = new HttpEntity<>(user, headers); ResponseEntity<User> response = restTemplate.postForEntity(url, request, User.class); return response.getBody(); } // 带请求头的复杂调用 public List<Order> getOrders(String token) { String url = "https://api.example.com/orders"; HttpHeaders headers = new HttpHeaders(); headers.setBearerAuth(token); // Bearer Token headers.set("X-Request-Id", UUID.randomUUID().toString()); HttpEntity<String> entity = new HttpEntity<>(headers); ResponseEntity<Order[]> response = restTemplate.exchange( url, HttpMethod.GET, entity, Order[].class ); return Arrays.asList(response.getBody()); } }

3.2 WebClient(响应式,Spring 5+ 推荐)

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; @Service public class WebClientService { private final WebClient webClient; public WebClientService(WebClient.Builder builder) { this.webClient = builder .baseUrl("https://api.example.com") .defaultHeader("Content-Type", "application/json") .build(); } // 同步调用(阻塞) public User getUserSync(Long id) { return webClient.get() .uri("/users/{id}", id) .retrieve() .bodyToMono(User.class) .block(); // 阻塞等待结果 } // 异步调用(非阻塞,推荐) public Mono<User> getUserAsync(Long id) { return webClient.get() .uri("/users/{id}", id) .retrieve() .bodyToMono(User.class); } // POST 请求 + 错误处理 public Mono<Order> createOrder(OrderRequest request) { return webClient.post() .uri("/orders") .bodyValue(request) .retrieve() .onStatus(HttpStatusCode::is4xxClientError, response -> Mono.error(new BusinessException("客户端错误"))) .onStatus(HttpStatusCode::is5xxServerError, response -> Mono.error(new SystemException("服务端错误"))) .bodyToMono(Order.class); } }

配合 Spring MVC 使用(Controller 层):

@RestController public class OrderController { @Autowired private WebClientService webClientService; @GetMapping("/orders/{id}") public Mono<Order> getOrder(@PathVariable Long id) { // 全程非阻塞,线程不会被占用 return webClientService.getOrderAsync(id); } }

四、生产级篇:接口调用框架封装

4.1 统一封装:带重试、超时、日志的 HTTP 工具

import lombok.extern.slf4j.Slf4j; import org.springframework.retry.annotation.Backoff; import org.springframework.retry.annotation.Retryable; import org.springframework.stereotype.Component; import org.springframework.web.client.ResourceAccessException; @Slf4j @Component public class HttpClientWrapper { @Autowired private RestTemplate restTemplate; /** * 带重试的 GET 请求 * 遇到 ResourceAccessException(连接超时、读取超时)时自动重试 */ @Retryable( retryFor = {ResourceAccessException.class}, maxAttempts = 3, backoff = @Backoff(delay = 1000, multiplier = 2) // 1s, 2s, 4s ) public <T> T getWithRetry(String url, Class<T> responseType) { log.info("发起请求: {}", url); long start = System.currentTimeMillis(); try { T result = restTemplate.getForObject(url, responseType); log.info("请求成功, 耗时{}ms", System.currentTimeMillis() - start); return result; } catch (Exception e) { log.error("请求失败: {}, 异常: {}", url, e.getMessage()); throw e; } } }

启用重试(Spring Boot):

@EnableRetry @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }

4.2 OpenFeign:声明式 HTTP 客户端(微服务首选)

Maven 依赖:

<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>

定义接口(像调用本地方法一样调用远程接口):

@FeignClient( name = "user-service", url = "https://api.example.com", configuration = FeignConfig.class, fallbackFactory = UserClientFallbackFactory.class ) public interface UserClient { @GetMapping("/users/{id}") User getUserById(@PathVariable("id") Long id); @PostMapping("/users") User createUser(@RequestBody User user); @GetMapping("/users") List<User> getUsersByIds(@RequestParam("ids") List<Long> ids); }

配置类:

public class FeignConfig { @Bean public Request.Options feignOptions() { // 连接超时 5s,读取超时 10s return new Request.Options(5, TimeUnit.SECONDS, 10, TimeUnit.SECONDS, true); } @Bean public Retryer feignRetryer() { // 初始间隔 100ms,最大间隔 1s,最多重试 3 次(不含首次) return new Retryer.Default(100, 1000, 3); } @Bean public Logger.Level feignLoggerLevel() { return Logger.Level.FULL; // 打印完整请求/响应 } }

降级处理(熔断时返回兜底数据):

@Component @Slf4j public class UserClientFallbackFactory implements FallbackFactory<UserClient> { @Override public UserClient create(Throwable cause) { log.error("UserClient 调用失败: {}", cause.getMessage()); return new UserClient() { @Override public User getUserById(Long id) { // 返回兜底用户 return User.builder() .id(id) .name("未知用户") .status("OFFLINE") .build(); } @Override public User createUser(User user) { throw new BusinessException("用户服务暂不可用,请稍后重试"); } @Override public List<User> getUsersByIds(List<Long> ids) { return Collections.emptyList(); } }; } }

启用 Feign:

@EnableFeignClients @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }

使用示例:

@Service public class OrderService { @Autowired private UserClient userClient; public OrderDetail getOrderDetail(Long orderId) { Order order = orderRepository.findById(orderId); // 像调用本地方法一样调用远程接口 User user = userClient.getUserById(order.getUserId()); return OrderDetail.builder() .order(order) .user(user) .build(); } }

五、Python 中的接口调用

5.1 requests 库(最常用)

import requests from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry # 创建带重试策略的 Session session = requests.Session() # 配置重试:连接错误重试3次,读取超时重试3次,状态码 500/502/503/504 重试3次 retries = Retry( total=3, backoff_factor=1, # 间隔 0s, 2s, 4s status_forcelist=[500, 502, 503, 504], allowed_methods=["HEAD", "GET", "POST", "PUT", "DELETE"] ) session.mount('https://', HTTPAdapter(max_retries=retries)) session.mount('http://', HTTPAdapter(max_retries=retries)) # GET 请求 def get_user(user_id: int) -> dict: url = f"https://api.example.com/users/{user_id}" response = session.get(url, timeout=(5, 10)) # (连接超时, 读取超时) response.raise_for_status() # 状态码 >= 400 时抛出异常 return response.json() # POST 请求 def create_user(user_data: dict) -> dict: url = "https://api.example.com/users" headers = {"Content-Type": "application/json"} response = session.post(url, json=user_data, headers=headers, timeout=10) return response.json() # 文件上传 def upload_file(file_path: str) -> dict: url = "https://api.example.com/upload" with open(file_path, 'rb') as f: files = {'file': ('report.pdf', f, 'application/pdf')} response = session.post(url, files=files) return response.json()

5.2 aiohttp(异步高性能)

import aiohttp import asyncio async def fetch_user(session: aiohttp.ClientSession, user_id: int) -> dict: url = f"https://api.example.com/users/{user_id}" async with session.get(url) as response: response.raise_for_status() return await response.json() async def main(): # 创建连接池,限制并发数 connector = aiohttp.TCPConnector(limit=100, limit_per_host=30) async with aiohttp.ClientSession( connector=connector, timeout=aiohttp.ClientTimeout(total=30) ) as session: # 并发请求 10 个用户 tasks = [fetch_user(session, i) for i in range(1, 11)] results = await asyncio.gather(*tasks, return_exceptions=True) for result in results: if isinstance(result, Exception): print(f"请求失败: {result}") else: print(f"用户: {result}") asyncio.run(main())

六、核心要点总结

维度建议
超时设置必须设置连接超时和读取超时,避免无限等待
连接池复用连接,减少 TCP 握手开销
重试策略仅对幂等操作(GET、PUT)重试,POST 需谨慎
异常处理区分网络异常、超时异常、业务异常
日志记录记录请求 URL、耗时、状态码,便于排查问题
序列化使用 Jackson/Gson 自动处理 JSON 与对象的映射
安全HTTPS 必用,敏感信息放 Header 而非 URL

七、选型建议

场景推荐方案
简单脚本/爬虫Pythonrequests
Android 开发OkHttp
Spring Boot 单体应用RestTemplate/WebClient
Spring Cloud 微服务OpenFeign+Ribbon
高并发异步场景WebClient/aiohttp
需要精细控制Apache HttpClient/OkHttp

接口调用的代码实现看似简单,但要做到稳定、高效、可维护,需要在超时控制、重试策略、连接管理、异常处理等方面下足功夫。希望本文能为你的接口调用实践提供有价值的参考。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/10 7:56:06

CBCX怎么样?围绕投教支持与信息透明度展开评测

当用户从更成熟的角度选择平台时&#xff0c;稳定体验和规范表达往往比单一卖点更重要。外汇服务行业进入更重视规范表达和用户保护的阶段后&#xff0c;平台评测也需要从多个细节展开。CBCX受到关注的原因&#xff0c;不只在于品牌露出&#xff0c;更在于它能否围绕稳定运行、…

作者头像 李华
网站建设 2026/6/10 7:52:16

C++11(三)

5.1 默认的移动构造和移动赋值 1. 默认成员函数概述 C98 的 6 个默认成员函数&#xff1a;构造函数、析构函数、拷贝构造函数、拷贝赋值重载、取地址重载、const取地址重载。 核心重点&#xff1a;前 4 个函数最为重要&#xff0c;后 2 个用处不大。默认行为&#xff1a;如果不…

作者头像 李华
网站建设 2026/6/10 7:50:17

计算机毕业设计之基于Python的民族味蕾共享平台的设计与实现

随着信息技术的飞速发展和互联网的普及&#xff0c;线上管理平台已成为当今社会经济发展的重要驱动力之一。本研究旨在设计并实现一个基于Django的民族味蕾共享平台&#xff0c;在技术选择上&#xff0c;本项目采用了Python语言&#xff0c;MySQL数据库编程&#xff0c;使用dja…

作者头像 李华
网站建设 2026/6/10 7:50:09

如何快速永久保存B站视频:m4s-converter完整使用教程

如何快速永久保存B站视频&#xff1a;m4s-converter完整使用教程 【免费下载链接】m4s-converter 一个跨平台小工具&#xff0c;将bilibili缓存的m4s格式音视频文件合并成mp4 项目地址: https://gitcode.com/gh_mirrors/m4/m4s-converter 还在为B站视频突然下架而烦恼吗…

作者头像 李华