spring 发送http请求 RestTemplate、WebClient

Spring HTTP 请求:RestTemplate 与 WebClient 比较
本文介绍了Spring中用于发送HTTP请求的两种方式:RestTemplate和WebClient。RestTemplate是同步的,适用于简单场景,而WebClient支持非阻塞和响应式交互。RestTemplate通过HttpMessageConverter自动处理Content-Type,支持Multipart/form-data和application/x-www-form-urlencoded。WebClient是Spring WebFlux的一部分,提供同步和异步操作,适合高并发和流式处理。
部署运行你感兴趣的模型镜像

spring 发送http的方法

spring发送http一共有两个方式,RestTemplateWebClient

RestTemplate

RestTemplate是spring推出的第一代Rest Client,它只能发送同步http请求,基于底层httpclient库,它暴露了同步的、简单的模板方法。
RestTemplate默认使用java.net.HttpURLConnection来发送请求,可以使用其它实现了ClientHttpRequestFactory接口http库,比如Apache HttpComponents、Netty、OkHttp,例如使用Apache HttpComponents

RestTemplate template = new RestTemplate(new HttpComponentsClientHttpRequestFactory());

ClientHttpRequestFactory 暴露了配置选项,比如凭证、连接池。java.net实现版本对错误的状态代码(比如401)会抛出异常,如果这是一个问题,请切换为其他http库。

uri

RestTemplate可以接受uri templateuri template variable两个参数,uri template variable就是uri的参数值,要么是String可变参数、要么就是Map<String,String>

  • String可变参数
//42,21就是uri template variable
String result = restTemplate.getForObject(
        "https://example.com/hotels/{hotel}/bookings/{booking}", String.class, "42", "21");
Map<String, String> vars = Collections.singletonMap("hotel", "42");
  • Map<String,String>
Map<String, String> vars = Collections.singletonMap("hotel", "42");
String result = restTemplate.getForObject(
        "https://example.com/hotels/{hotel}/rooms/{hotel}", String.class, vars);
  • uri template会自动编码
restTemplate.getForObject("https://example.com/hotel list", String.class);
// Results in request to "https://example.com/hotel%20list"
Header

使用exchange方法来指定请求头

String uriTemplate = "https://example.com/hotels/{hotel}";
URI uri = UriComponentsBuilder.fromUriString(uriTemplate).build(42);
RequestEntity<Void> requestEntity = RequestEntity.get(uri)
        .header(("MyRequestHeader", "MyValue")
        .build();
ResponseEntity<String> response = template.exchange(requestEntity, String.class);
String responseHeader = response.getHeaders().getFirst("MyResponseHeader");
String body = response.getBody();
Body

RestTemplate使用HttpMessageConverter来序列化和反序列化请求和响应数据。
发送post时,对象被序列化到请求体,比如

//person被序列化到请求体中
URI location = template.postForLocation("https://example.com/people", person);
public <T> T postForObject(String url, @Nullable Object request, Class<T> responseType,
			Object... uriVariables)

你不需要明确设置Content-Type请求头,在大多数情况下,根据请求方法参数Object request选择message converter,message converter会相应的设置Content-Type请求头。如有必要你可以使用exchange方法来明确提供Content-Type请求头;

Get方法时,响应体会反序列化为一个输出对象,如下

Person person = restTemplate.getForObject("https://example.com/people/{id}", Person.class, 42);

Accept 请求头不需要显式设置,在大多数情况下,基于请求方法参数responseType会选择一个兼容的message converter,它会添加Accept头。可使用exchange方法显式指定Accept头。

MessageConverter

Spring-web模块包含HttpMessageConverter约定,约定指的是通过InputStream和OutputStream,HttpMessageConverter如何读取http请求body和写入http响应。
spring web框架提供了主要MIME type的HttpMessageConverter实现,在客户端RestTemplate来注册这些实现,在服务器端RequestMethodHandlerAdapter 来注册。
内建的MessageConverter有

  • StringHttpMessageConverter,读取及写入string,支持读取所有的MIME type(text/*),写入到响应时Content-Type : text/plain.
  • FormHttpMessageConverter,支持Content-Type:application/x-www-form-urlencoded,也支持multipart/form-data
  • ByteArrayHttpMessageConverter,支持Content-Type:application/octet-stream,可以从请求读取字节数组,可以将字节数组写入响应
  • MarshallingHttpMessageConverter,支持Content-Type为text/xml 、application/xml.
  • MappingJackson2HttpMessageConverter,支持json
  • MappingJackson2XmlHttpMessageConverter,支持Content-Type为application/xml.
  • SourceHttpMessageConverter,支持Content-Type为text/xml 、application/xml.
  • BufferedImageHttpMessageConverter,支持从请求和响应读取或写入java.awt.image.BufferedImage
Jackson JSON Views

可以指定Jackson JSON Views来序列化一部分对象属性而不是全部

MappingJacksonValue value = new MappingJacksonValue(new User("eric", "7!jd#h23"));
value.setSerializationView(User.WithoutPasswordView.class);
RequestEntity<MappingJacksonValue> requestEntity =
    RequestEntity.post(new URI("https://example.com/user")).body(value);
ResponseEntity<String> response = template.exchange(requestEntity, String.class);
Multipart

使用MultiValueMap<String, Object>发送Multipart Data,map中的值可以是Object(表示部分内容)、可以是Resource(表示文件)、可以是HttpEntity (表示带有header的部分内容)

MultiValueMap<String, Object> parts = new LinkedMultiValueMap<>();

parts.add("fieldPart", "fieldValue");
parts.add("filePart", new FileSystemResource("...logo.png"));
parts.add("jsonPart", new Person("Jason"));

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_XML);
parts.add("xmlPart", new HttpEntity<>(myBean, headers));

在大多数情况下不需要设置Content-Type,基于选择的HttpMessageConverter会决定Content-Type,比如Resource的时候,根据文件后缀决定;
如果MultiValueMap包含至少一个非String值,那么Content-Type会被设置为multipart/form-data ,如果MultiValueMap 都是String 那么 Content-Type默认是 application/x-www-form-urlencoded. 如果有必要, Content-Type也可以明确指定.

  • 发送application/x-www-form-urlencoded
    • 默认的,如果请求参数是MultiValueMap,并且所有的值都是字符串,则是表单键值对,保险起见可以设置一下Content-Type,因为通常发送的数据不可能全部都是字符串。
  • 发送multipart/form-data
    • 默认的,如果请求参数是MultiValueMap,并且只要有一个非String的值,则是multipart/form-data。
  • 发送json
    • 直接发送对象就可以了,不需要设置Content-Type,比如
User user = new User();
restTemplate.postForObject("url", user, 响应类.class);

WebClient

WebClient是一个non-blocking,响应式客户端,支持同步、异步请求和流式的场景

In contrast to RestTemplate, WebClient supports the following:

  • Non-blocking I/O.
  • Reactive Streams back pressure.
  • High concurrency with fewer hardware resources.
  • Functional-style, fluent API that takes advantage of Java 8 lambdas.
  • Synchronous and asynchronous interactions.
  • Streaming up to or streaming down from a server.
创建WebClient

最简单的方式通过静态工厂方法

WebClient.create()
WebClient.create(String baseUrl)

也可以使用builder(),这种有更多选项

uriBuilderFactory: Customized UriBuilderFactory to use as a base URL.

defaultUriVariables: default values to use when expanding URI templates.

defaultHeader: Headers for every request.

defaultCookie: Cookies for every request.

defaultRequest: Consumer to customize every request.

filter: Client filter for every request.

exchangeStrategies: HTTP message reader/writer customizations.

clientConnector: HTTP client library settings.

比如,

WebClient client = WebClient.builder()
        .codecs(configurer -> ... )
        .build();

一旦创建,WebClient就不能更改了,但可以copy然后再修改

WebClient client1 = WebClient.builder()
        .filter(filterA).filter(filterB).build();

WebClient client2 = client1.mutate()
        .filter(filterC).filter(filterD).build();

// client1 has filterA, filterB
// client2 has filterA, filterB, filterC, filterD

//retrieve方法用来解压出response

WebClient client = WebClient.create("https://example.org");

Mono<ResponseEntity<Person>> result = client.get()
        .uri("/persons/{id}", id).accept(MediaType.APPLICATION_JSON)
        .retrieve()
        .toEntity(Person.class);

//仅得到body

Mono<Person> result = client.get()
        .uri("/persons/{id}", id).accept(MediaType.APPLICATION_JSON)
        .retrieve()
        .bodyToMono(Person.class);

//默认的4xx和5xx会引起WebClientResponseException,可以自定义错误处理

Mono<Person> result = client.get()
        .uri("/persons/{id}", id).accept(MediaType.APPLICATION_JSON)
        .retrieve()
        .onStatus(HttpStatus::is4xxClientError, response -> ...)
        .onStatus(HttpStatus::is5xxServerError, response -> ...)
        .bodyToMono(Person.class);

发送同步请求

Person person = client.get().uri("/person/{id}", i).retrieve()
    .bodyToMono(Person.class)
    .block();
List<Person> persons = client.get().uri("/persons").retrieve()
    .bodyToFlux(Person.class)
    .collectList()
    .block();

总结

  • RestTemplate是spring推出的第一代rest client,它提供了简单的、同步的请求模板方法,默认的不用设置Content-Type,根据请求参数会自动设置Content-Type,如果MultiValueMap有非String值,则发送Multipart/form-data,如果是字符串,则默认是键值对形式(Content-Type:application/x-www-form-urlencoded),也可以明确指定。使用execute、change是通用请求方法,可以指定content-type等参数。
  • WebClient是spring推出的第二代rest client,提供了同步的、异步的、非阻塞式http请求方法,属于Spring WebFlux的一部分,目前项目中并没有IO密集型的业务,所以暂时不用这种方式了,继续使用RestTemplate

您可能感兴趣的与本文相关的镜像

FLUX.1-dev

FLUX.1-dev

图片生成
FLUX

FLUX.1-dev 是一个由 Black Forest Labs 创立的开源 AI 图像生成模型版本,它以其高质量和类似照片的真实感而闻名,并且比其他模型更有效率

Spring提供了多种发送HTTP请求的API,其中最常用的是使用RestTemplateWebClient。 1. RestTemplate: RestTemplateSpring提供的传统的同步的HTTP客户端,它提供了多种发送HTTP请求的方法,包括GET、POST、PUT、DELETE等。 使用RestTemplate发送GET请求的示例代码如下: ```java RestTemplate restTemplate = new RestTemplate(); String response = restTemplate.getForObject("http://example.com/api/resource", String.class); ``` 使用RestTemplate发送POST请求的示例代码如下: ```java RestTemplate restTemplate = new RestTemplate(); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); Map<String, Object> requestBody = new HashMap<>(); requestBody.put("key1", "value1"); requestBody.put("key2", "value2"); HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(requestBody, headers); ResponseEntity<String> responseEntity = restTemplate.postForEntity("http://example.com/api/resource", requestEntity, String.class); String response = responseEntity.getBody(); ``` 2. WebClient: WebClientSpring 5引入的非阻塞的异步HTTP客户端,它基于Reactor提供了更高效的性能和更好的响应式编程支持。 使用WebClient发送GET请求的示例代码如下: ```java WebClient webClient = WebClient.create(); Mono<String> responseMono = webClient.get() .uri("http://example.com/api/resource") .retrieve() .bodyToMono(String.class); responseMono.subscribe(response -> { // 处理响应结果 }); ``` 使用WebClient发送POST请求的示例代码如下: ```java WebClient webClient = WebClient.create(); Mono<String> responseMono = webClient.post() .uri("http://example.com/api/resource") .contentType(MediaType.APPLICATION_JSON) .bodyValue(requestBody) .retrieve() .bodyToMono(String.class); responseMono.subscribe(response -> { // 处理响应结果 }); ``` 以上是Spring发送HTTP请求的两种常用方式,你可以根据实际需求选择使用RestTemplate还是WebClient
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值