从入门到实战详解后端实现接口调用的完整代码(Java/Python)

Written by

in

文章目录
  • 维度 建议 超时设置 必须设置连接超时和读取超时,避免无限等待 连接池 复用连接,减少 TCP 握手开销 重试策略 仅对幂等操作(GET、PUT)重试,POST 需谨慎 异常处理 区分网络异常、超时异常、业务异常 日志记录 记录请求 URL、耗时、状态码,便于排查问题 序列化 使用 Jackson/Gson 自动处理 JSON 与对象的映射 安全 HTTPS 必用,敏感信息放 Header 而非 URL
  • 场景 推荐方案 简单脚本/爬虫 Python requests Android 开发 OkHttp Spring Boot 单体应用 RestTemplate / WebClient Spring Cloud 微服务 OpenFeign + Ribbon 高并发异步场景 WebClient / aiohttp 需要精细控制 Apache HttpClient / OkHttp 接口调用的代码实现看似简单,但要做到稳定、高效、可维护,需要在超时控制、重试策略、连接管理、异常处理等方面下足功夫。希望本文能为你的接口调用实践提供有价值的参考。 以上就是从入门到实战详解后端实现接口调用的完整代码(Java/Python)的详细内容,更多关于后端接口调用方案的资料请关注风君子博客其它相关文章! 您可能感兴趣的文章: python调用dubbo接口的实现步骤 Python调用Java接口失败(Java日志打印警告:JSON parse error:xxxx)的解决方案 Python调用API接口实现规范获取官方数据 Python调用Java接口实现互相SM2加签验签 java调用第三方接口实现流式输出的示例代码 Java统计接口调用频率的五种方案及对比详解 Java调用UniHttp接口请求失败的三种解决策略
  • 目录
    • 一、基础篇:HTTP 请求的核心原理
      • 1.1 HTTP 请求的本质
      • 1.2 最基础的接口调用(原生 Java)
    • 二、进阶篇:使用成熟 HTTP 客户端
      • 2.1 Apache HttpClient(Java 经典方案)
      • 2.2 OkHttp(轻量高效,Android 首选)
    • 三、实战篇:Spring 生态中的接口调用
      • 3.1 RestTemplate(Spring 经典方案)
      • 3.2 WebClient(响应式,Spring 5+ 推荐)
    • 四、生产级篇:接口调用框架封装
      • 4.1 统一封装:带重试、超时、日志的 HTTP 工具
      • 4.2 OpenFeign:声明式 HTTP 客户端(微服务首选)
    • 五、Python 中的接口调用
      • 5.1 requests 库(最常用)
      • 5.2 aiohttp(异步高性能)
    • 六、核心要点总结
      • 七、选型建议

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

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

        请求行:    GET /api/users/1 HTTP/1.1

        请求头:  

        Host: api.example.com
        Content-Type: application/json
        Authorization: Bearer xxx

        请求体:    {"name": "Alice"}   (GET请求通常无请求体)

        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 客户端库。

        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);
                }
            }
        }
        

        Maven 依赖:

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

        同步调用示例:

        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());
                }
            }
        });
        

        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());
            }
        }
        

        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);
            }
        }
        

        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);
            }
        }
        

        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();
            }
        }
        

        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()

        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

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

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

        以上就是从入门到实战详解后端实现接口调用的完整代码(Java/Python)的详细内容,更多关于后端接口调用方案的资料请关注风君子博客其它相关文章!

        您可能感兴趣的文章:

        • python调用dubbo接口的实现步骤
        • Python调用Java接口失败(Java日志打印警告:JSON parse error:xxxx)的解决方案
        • Python调用API接口实现规范获取官方数据
        • Python调用Java接口实现互相SM2加签验签
        • java调用第三方接口实现流式输出的示例代码
        • Java统计接口调用频率的五种方案及对比详解
        • Java调用UniHttp接口请求失败的三种解决策略

        站内搜索