WebClient HTTP 请求问题处理模板(泛型响应、忽略 SSL 证书等)

我命由我12345 2024-09-12 12:33:10 阅读 98

一、请求大数据

1、问题案例
(1)Server

该接口返回一段大小为 1MB 的字符串

<code>@GetMapping("/testBigData")

public String testBigData() {

int targetSize = 1024 * 1024; // 1MB

StringBuilder sb = new StringBuilder(targetSize);

for (int i = 0; i < targetSize; i++) sb.append('A');

String largeString = sb.toString();

return largeString;

}

(2)Client

WebClient webClient = WebClient.create();

Mono<String> response = webClient.get()

.uri("http://127.0.0.1:9999/test/testBigData")

.retrieve()

.bodyToMono(String.class);

response.subscribe(result -> {

System.out.println("请求成功,结果长度为:" + result.length());

}, throwable -> {

throwable.printStackTrace();

});

输出结果,因为数据量超过了设定的最大限制而报错

org.springframework.web.reactive.function.client.WebClientResponseException: 200 OK from GET http://127.0.0.1:9999/test/testBigData

Caused by: org.springframework.core.io.buffer.DataBufferLimitException: Exceeded limit on max bytes to buffer : 262144

2、处理策略

调整数据量的最大限制

int size = 2 * 1024 * 1024;

ExchangeStrategies strategies = ExchangeStrategies.builder()

.codecs(codecs -> codecs.defaultCodecs().maxInMemorySize(size))

.build();

WebClient webClient = WebClient.builder()

.exchangeStrategies(strategies)

.build();

Mono<String> response = webClient.get()

.uri("http://127.0.0.1:9999/test/testBigData")

.retrieve()

.bodyToMono(String.class);

response.subscribe(result -> {

System.out.println("请求成功,结果长度为:" + result.length());

}, throwable -> {

throwable.printStackTrace();

});


二、不使用缓冲区请求图片

1、问题案例
(1)Server

application.yaml

server:

port: 9999

spring:

mvc:

static-path-pattern: /file/download/**

web:

resources:

static-locations: file:D:/fileUpload/

(2)Client

WebClient webClient = WebClient.create();

Mono<byte[]> response = webClient.get()

.uri("http://127.0.0.1:9999/file/download/1.png")

.accept(MediaType.IMAGE_JPEG, MediaType.IMAGE_PNG)

.retrieve()

.bodyToMono(byte[].class);

response.subscribe(result -> {

System.out.println("请求成功");

if (result != null) System.out.println("result length is " + result.length);

}, throwable -> {

throwable.printStackTrace();

});

输出结果,不使用 DataBuffer,会因为数据量超过了设定的最大限制而报错

org.springframework.web.reactive.function.client.WebClientResponseException: 200 OK from GET http://127.0.0.1:9999/file/download/1.png

Caused by: org.springframework.core.io.buffer.DataBufferLimitException: Exceeded limit on max bytes to buffer : 262144

2、处理策略

调整数据量的最大限制

int size = 10 * 1024 * 1024;

ExchangeStrategies strategies = ExchangeStrategies.builder()

.codecs(codecs -> codecs.defaultCodecs().maxInMemorySize(size))

.build();

WebClient webClient = WebClient.builder()

.exchangeStrategies(strategies)

.build();

Mono<byte[]> response = webClient.get()

.uri("http://127.0.0.1:9999/file/download/1.png")

.accept(MediaType.IMAGE_JPEG, MediaType.IMAGE_PNG)

.retrieve()

.bodyToMono(byte[].class);

response.subscribe(result -> {

System.out.println("请求成功");

if (result != null) System.out.println("result length is " + result.length);

}, throwable -> {

throwable.printStackTrace();

});


三、泛型响应

1、问题案例
(1)Entity

Person.java

@Data

@NoArgsConstructor

@AllArgsConstructor

public class Person<T> {

private String name;

private int age;

private T thing;

}

Computer.java

@Data

@NoArgsConstructor

@AllArgsConstructor

public class Computer {

private String name;

private Double price;

}

(2)Server

@GetMapping("/testGeneric")

public Person<Computer> testGeneric() {

Computer computer = new Computer("联想电脑", 8999.0);

Person<Computer> person = new Person<Computer>("张三", 20, computer);

return person;

}

(3)Client

WebClient webClient = WebClient.create();

Mono<Person> response = webClient.get()

.uri("http://127.0.0.1:9999/test/testGeneric")

.retrieve()

.bodyToMono(Person.class);

response.subscribe(person -> {

System.out.println("请求成功");

System.out.println(person);

Computer computer = (Computer) person.getThing();

System.out.println(computer);

}, throwable -> {

System.out.println("请求失败,结果为:" + throwable.getMessage());

});

输出结果,对于嵌套的泛型强转失败

请求成功

Person(name=张三, age=20, thing={name=联想电脑, price=8999.0})

请求失败,结果为:class java.util.LinkedHashMap cannot be cast to class com.zy.api.Computer (java.util.LinkedHashMap is in module java.base of loader 'bootstrap'; com.zy.api.Computer is in unnamed module of loader 'app')

2、处理策略

正确指示 bodyToMono 方法

WebClient webClient = WebClient.create();

Mono<Person<Computer>> response = webClient.get()

.uri("http://127.0.0.1:9999/test/testGeneric")

.retrieve()

.bodyToMono(new ParameterizedTypeReference<Person<Computer>>() {

});

response.subscribe(person -> {

System.out.println("请求成功");

System.out.println(person);

Computer computer = person.getThing();

System.out.println(computer);

}, throwable -> {

System.out.println("请求失败,结果为:" + throwable.getMessage());

});


四、跟随重定向响应

1、问题案例
(1)Server

server:

port: 9999

spring:

mvc:

static-path-pattern: /file/download/**

web:

resources:

static-locations: file:D:/fileUpload/

@GetMapping("/testRedirect2Image")

public ResponseEntity testRedirect2Image() {

return ResponseEntity.status(HttpStatus.SEE_OTHER)

.header("Location", "http://127.0.0.1:9999/file/download/1.png")

.build();

}

(2)Client

WebClient webClient = WebClient.create();

webClient.get()

.uri("http://127.0.0.1:9999/test/testRedirect2Image")

.accept(MediaType.IMAGE_JPEG, MediaType.IMAGE_PNG) // 指定了客户端期望接受的响应内容类型

.retrieve() // 获取响应

.bodyToFlux(DataBuffer.class) // 将响应体转换为 Flux<DataBuffer>

.reduce(new org.apache.tomcat.util.http.fileupload.ByteArrayOutputStream(), (baos, dataBuffer) -> {

try {

byte[] bytes = new byte[dataBuffer.readableByteCount()];

dataBuffer.read(bytes);

baos.write(bytes);

DataBufferUtils.release(dataBuffer);

} catch (IOException e) {

e.printStackTrace();

DataBufferUtils.release(dataBuffer);

return null;

}

return baos;

})

.map(byteArrayOutputStream -> {

if (byteArrayOutputStream == null) return null;

return byteArrayOutputStream.toByteArray();

})

.subscribe(result -> {

if (result == null) {

System.out.println("result is null");

return;

}

System.out.println("result length: " + result.length);

}, throwable -> {

throwable.printStackTrace();

});

输出结果,默认不会跟随重定向响应

result length: 0

2、处理策略

收到开启跟随重定向响应

HttpClient httpClient = HttpClient.create()

.followRedirect(true); // 允许跟随重定向

WebClient webClient = WebClient.builder()

.clientConnector(new ReactorClientHttpConnector(httpClient))

.build();

webClient.get()

.uri("http://127.0.0.1:9999/test/testRedirect2Image")

.accept(MediaType.IMAGE_JPEG, MediaType.IMAGE_PNG) // 指定了客户端期望接受的响应内容类型

.retrieve() // 获取响应

.bodyToFlux(DataBuffer.class) // 将响应体转换为 Flux<DataBuffer>

.reduce(new org.apache.tomcat.util.http.fileupload.ByteArrayOutputStream(), (baos, dataBuffer) -> {

try {

byte[] bytes = new byte[dataBuffer.readableByteCount()];

dataBuffer.read(bytes);

baos.write(bytes);

DataBufferUtils.release(dataBuffer);

} catch (IOException e) {

e.printStackTrace();

DataBufferUtils.release(dataBuffer);

return null;

}

return baos;

})

.map(byteArrayOutputStream -> {

if (byteArrayOutputStream == null) return null;

return byteArrayOutputStream.toByteArray();

})

.subscribe(result -> {

if (result == null) {

System.out.println("result is null");

return;

}

System.out.println("result length: " + result.length);

}, throwable -> {

throwable.printStackTrace();

});


五、SSL 证书

1、问题案例

WebClient webClient = WebClient.create();

Mono<byte[]> response = webClient.get()

.uri(url)

.accept(MediaType.IMAGE_JPEG, MediaType.IMAGE_PNG)

.retrieve()

.bodyToFlux(DataBuffer.class)

.reduce(new ByteArrayOutputStream(), (baos, dataBuffer) -> {

try {

byte[] bytes = new byte[dataBuffer.readableByteCount()];

dataBuffer.read(bytes);

baos.write(bytes);

DataBufferUtils.release(dataBuffer);

} catch (IOException e) {

e.printStackTrace();

DataBufferUtils.release(dataBuffer);

return null;

}

return baos;

})

.map(byteArrayOutputStream -> {

if (byteArrayOutputStream == null) return null;

return byteArrayOutputStream.toByteArray();

});

response.subscribe(result -> {

System.out.println("请求成功");

if (result != null) System.out.println("result length is " + result.length);

}, throwable -> {

throwable.printStackTrace();

});

输出结果

org.springframework.web.reactive.function.client.WebClientRequestException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

2、忽略 SSL 证书

SslContext context = SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE).build();

HttpClient httpClient = HttpClient.create().secure(t -> t.sslContext(context));

WebClient webClient = WebClient.builder()

.clientConnector(new ReactorClientHttpConnector(httpClient))

.build();

Mono<byte[]> response = webClient.get()

.uri(url)

.accept(MediaType.IMAGE_JPEG, MediaType.IMAGE_PNG)

.retrieve()

.bodyToFlux(DataBuffer.class)

.reduce(new ByteArrayOutputStream(), (baos, dataBuffer) -> {

try {

byte[] bytes = new byte[dataBuffer.readableByteCount()];

dataBuffer.read(bytes);

baos.write(bytes);

DataBufferUtils.release(dataBuffer);

} catch (IOException e) {

e.printStackTrace();

DataBufferUtils.release(dataBuffer);

return null;

}

return baos;

})

.map(byteArrayOutputStream -> {

if (byteArrayOutputStream == null) return null;

return byteArrayOutputStream.toByteArray();

});

response.subscribe(result -> {

System.out.println("请求成功");

if (result != null) System.out.println("result length is " + result.length);

}, throwable -> {

throwable.printStackTrace();

});



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。