文档站点
Skip to content

HTTP 客户端 ​

Laravel 用 Http::get() / Http::post()(Guzzle 封装)发起外部请求;Spring Boot 3.x 的现代答案是 RestClient(同步,Spring 6.1+ 推荐)和 WebClient(响应式)。这篇主推 RestClient,它最接近 Http:: 的用法。

RestClient:最接近 Laravel Http 的写法 ​

基础用法 ​

java
@Service
public class WeatherService {

    private final RestClient restClient = RestClient.create();

    public String getWeather(String city) {
        return restClient.get()
                .uri("https://api.weather.com/v1/{city}", city)   // 路径变量
                .retrieve()                                        // 发送并接收
                .body(String.class);                               // 解析为 String
    }
}

对应 Laravel:

php
$response = Http::get("https://api.weather.com/v1/{$city}");
return $response->body();

GET 带查询参数 + 解析 JSON ​

java
public Map<String, Object> search(String q, int page) {
    return restClient.get()
            .uri(uriBuilder -> uriBuilder
                    .path("/search")
                    .queryParam("q", q)
                    .queryParam("page", page)
                    .build())
            .retrieve()
            .body(Map.class);
}

POST + JSON 请求体 ​

java
public Map<String, Object> create(Map<String, Object> payload) {
    return restClient.post()
            .uri("https://api.example.com/posts")
            .contentType(MediaType.APPLICATION_JSON)
            .body(payload)
            .retrieve()
            .body(Map.class);
}

TIP

RestClient 底层用 Jackson 自动把对象序列化为 JSON、把响应 JSON 反序列化为指定类型 —— 和 Laravel 里 Http::asJson()->post(...) 自动 JSON 化一致。

自定义请求头 ​

java
restClient.post()
        .uri(url)
        .header("Authorization", "Bearer " + token)
        .header("Accept-Language", "zh-CN")
        ...

把接口封装成客户端类(推荐) ​

Laravel 社区会把第三方 API 封装成 Service;Java 也一样,还能把 RestClient 做成单例 Bean:

java
@Service
public class PaymentApiClient {

    private final RestClient client;

    public PaymentApiClient(RestClient.Builder builder) {
        // 统一 Base URL、超时、日志,所有请求自动带上
        this.client = builder
                .baseUrl("https://api.payment.com/v2")
                .defaultHeader("Authorization", "Bearer " + System.getenv("PAY_TOKEN"))
                .build();
    }

    public Payment createOrder(Map<String, Object> order) {
        return client.post()
                .uri("/orders")
                .body(order)
                .retrieve()
                .body(Payment.class);    // 直接反序列化成 DTO
    }
}

什么时候用这种封装?

任何「外部服务」都建议封装成 Client 类,理由和 Laravel 封装第三方 API 一样:

  • 接口变更只改一处
  • 方便测试时 mock
  • 统一超时/鉴权/日志

错误处理 ​

Laravel Http::throw() 抛异常;Spring RestClient 默认非 2xx 会抛 RestClientResponseException:

java
try {
    return client.get().uri(url).retrieve().body(Payment.class);
} catch (RestClientResponseException e) {
    // e.getStatusCode()、e.getResponseBodyAsString()
    log.warn("支付接口返回异常: {} {}", e.getStatusCode(), e.getResponseBodyAsString());
    throw BusinessException.badRequest("支付服务暂时不可用");
}

也可以在请求时自定义错误处理:

java
client.get()
        .uri(url)
        .retrieve()
        .onStatus(HttpStatusCode::is4xxClientError,
                (request, response) -> { throw new BusinessException(400, "请求参数问题"); })
        .body(Payment.class);

超时配置 ​

java
RestClient client = RestClient.builder()
        .requestFactory(new JdkClientHttpRequestFactory(HttpClient.newBuilder()
                .connectTimeout(Duration.ofSeconds(5))      // 连接超时
                .build()))
        .baseUrl(url)
        .build();

WebClient:响应式场景才用 ​

WebClient 是 Spring WebFlux 时代的产物,异步非阻塞。同一套写法能返回「异步结果」,适合高并发 I/O 密集场景:

java
@Service
public class AsyncWeatherService {
    private final WebClient webClient = WebClient.create();

    public Mono<String> getWeather(String city) {
        return webClient.get()
                .uri("https://api.weather.com/v1/{city}", city)
                .retrieve()
                .bodyToMono(String.class);
    }
}

怎么选

场景用哪个
传统 MVC 项目同步调外部 APIRestClient(简单、直观)
高并发异步、WebFlux 项目WebClient
只想发个简单请求RestClient
RestClient 内部是同步阻塞的,读起来和 Http:: 一模一样;WebClient 是响应式的,上手成本高。没有特殊理由选 RestClient。

对照速查 ​

需求LaravelRestClient
GETHttp::get($url)client.get().uri(url).retrieve()
POST JSONHttp::asJson()->post($url, $data)client.post().contentType(JSON).body(data)
路径参数Http::get(".../{$id}").uri(url, id)
查询参数Http::get($url, ['q' => $q])uriBuilder.queryParam("q", q)
请求头Http::withHeaders([...]).header(name, value)
抛错Http::throw()默认自动抛 RestClientResponseException
超时Http::timeout(5)自定义 requestFactory

面向 PHP / Laravel 开发者的 Spring Boot 中文文档