Java SpringBoot5WebClient在检查HTTP响应头之前首先验证HTTPStatus
我试图用Spring5WebClient确认HTTP响应头的值,但前提是web调用使用HTTP200状态代码进行响应。在本用例中,如果身份验证未成功,则API调用返回HTTP 401,而不存在响应头。下面的代码在功能上是有效的,但它会进行两次web调用(因为我阻塞了两次)。除了只阻塞HTTP响应头,并在头不存在时为NPE设置try/catch之外,还有什么“更干净”的方法可以做到这一点吗Java SpringBoot5WebClient在检查HTTP响应头之前首先验证HTTPStatus,java,spring,spring-boot,spring-webflux,Java,Spring,Spring Boot,Spring Webflux,我试图用Spring5WebClient确认HTTP响应头的值,但前提是web调用使用HTTP200状态代码进行响应。在本用例中,如果身份验证未成功,则API调用返回HTTP 401,而不存在响应头。下面的代码在功能上是有效的,但它会进行两次web调用(因为我阻塞了两次)。除了只阻塞HTTP响应头,并在头不存在时为NPE设置try/catch之外,还有什么“更干净”的方法可以做到这一点吗 import java.net.URI; import java.time.Duration; impor
import java.net.URI;
import java.time.Duration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.ClientRequest;
import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.reactive.function.client.ExchangeFunction;
import org.springframework.web.reactive.function.client.ExchangeFunctions;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@SpringBootApplication
public class ContentCheckerApplication {
private static final Logger LOGGER = LoggerFactory.getLogger(ContentCheckerApplication.class);
private ExchangeFunction exchange = ExchangeFunctions.create(new ReactorClientHttpConnector());
public static void main(String[] args) {
SpringApplication app = new SpringApplication(ContentCheckerApplication.class);
// prevent SpringBoot from starting a web server
app.setWebApplicationType(WebApplicationType.NONE);
app.run(args);
}
@Bean
public CommandLineRunner myCommandLineRunner() {
return args -> {
// Our reactive code will be declared here
LinkedMultiValueMap<String, String> formData = new LinkedMultiValueMap<String, String>();
formData.add("username", args[2]);
formData.add("password", args[3]);
ClientRequest request = ClientRequest.method(HttpMethod.POST, new URI(args[0]+"/api/token"))
.body(BodyInserters.fromFormData(formData)).build();
Mono<ClientResponse> mresponse = exchange.exchange(request);
Mono<String> mnewToken = mresponse.map(response -> response.headers().asHttpHeaders().getFirst("WSToken"));
LOGGER.info("Blocking for status code...");
HttpStatus statusCode = mresponse.block(Duration.ofMillis(1500)).statusCode();
LOGGER.info("Got status code!");
if (statusCode.value() == 200) {
String newToken = mnewToken.block(Duration.ofMillis(1500));
LOGGER.info("Auth token is: " + newToken);
} else {
LOGGER.info("Unable to authenticate successfully! Status code: "+statusCode.value());
}
};
}
}
导入java.net.URI;
导入java.time.Duration;
导入org.slf4j.Logger;
导入org.slf4j.LoggerFactory;
导入org.springframework.boot.CommandLineRunner;
导入org.springframework.boot.SpringApplication;
导入org.springframework.boot.WebApplicationType;
导入org.springframework.boot.autoconfigure.springboot应用程序;
导入org.springframework.context.annotation.Bean;
导入org.springframework.http.HttpMethod;
导入org.springframework.http.HttpStatus;
导入org.springframework.http.client.reactive.ReactorClientHttpConnector;
导入org.springframework.util.LinkedMultiValueMap;
导入org.springframework.web.reactive.function.BodyInserters;
导入org.springframework.web.reactive.function.client.ClientRequest;
导入org.springframework.web.reactive.function.client.ClientResponse;
导入org.springframework.web.reactive.function.client.ExchangeFunction;
导入org.springframework.web.reactive.function.client.ExchangeFunctions;
导入reactor.core.publisher.Flux;
导入reactor.core.publisher.Mono;
@SpringBoot应用程序
公共类ContentCheckerApplication{
私有静态最终记录器Logger=LoggerFactory.getLogger(ContentCheckerApplication.class);
私有ExchangeFunction exchange=ExchangeFunctions.create(新建ReactorClient TTPConnector());
公共静态void main(字符串[]args){
SpringApplication app=新的SpringApplication(ContentCheckerApplication.class);
//防止SpringBoot启动web服务器
app.setWebApplicationType(WebApplicationType.NONE);
应用程序运行(args);
}
@豆子
公共命令行运行程序myCommandLineRunner(){
返回参数->{
//我们的反应式代码将在这里声明
LinkedMultiValueMap formData=新LinkedMultiValueMap();
添加(“用户名”,参数[2]);
添加(“密码”,参数[3]);
ClientRequest=ClientRequest.method(HttpMethod.POST,新URI(args[0]+“/api/token”))
.body(BodyInserters.fromFormData(formData)).build();
Mono-mresponse=exchange.exchange(请求);
Mono mnewToken=mresponse.map(response->response.headers().asHttpHeaders().getFirst(“WSToken”);
LOGGER.info(“阻止状态代码…”);
HttpStatus statusCode=mresponse.block(持续时间为1500毫秒)).statusCode();
LOGGER.info(“获取状态代码!”);
如果(statusCode.value()==200){
字符串newToken=mnewToken.block(持续时间为1500毫米);
LOGGER.info(“身份验证令牌为:“+newToken”);
}否则{
LOGGER.info(“无法成功进行身份验证!状态代码:+statusCode.value());
}
};
}
}
多亏@M.Deinum的评论来指导我,我有以下代码,现在可以使用了
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpStatus;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.ExchangeFunction;
import org.springframework.web.reactive.function.client.ExchangeFunctions;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
@SpringBootApplication
public class ContentCheckerApplication {
private static final Logger LOGGER = LoggerFactory.getLogger(ContentCheckerApplication.class);
private ExchangeFunction exchange = ExchangeFunctions.create(new ReactorClientHttpConnector());
public static void main(String[] args) {
SpringApplication app = new SpringApplication(ContentCheckerApplication.class);
// prevent SpringBoot from starting a web server
app.setWebApplicationType(WebApplicationType.NONE);
app.run(args);
}
@Bean
public CommandLineRunner myCommandLineRunner() {
return args -> {
// Change some Netty defaults
ReactorClientHttpConnector connector = new ReactorClientHttpConnector(
options -> options.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 2000)
.compression(true)
.afterNettyContextInit(ctx -> {
ctx.addHandlerLast(new ReadTimeoutHandler(1500, TimeUnit.MILLISECONDS));
}));
LinkedMultiValueMap<String, String> formData = new LinkedMultiValueMap<String, String>();
formData.add("username", args[2]);
formData.add("password", args[3]);
WebClient webClient = WebClient.builder().clientConnector(connector).build();
Mono<String> tokenResult = webClient.post()
.uri( args[0] + "/api/token" )
.body( BodyInserters.fromFormData(formData))
.exchange()
.onErrorMap(ContentCheckerApplication::handleAuthTokenError)
.map(response -> {
if (HttpStatus.OK.equals(response.statusCode())) {
return response.headers().asHttpHeaders().getFirst("WSToken");
} else {
return "";
}
});
LOGGER.info("Subscribing for the result and then going to sleep");
tokenResult.subscribe(ContentCheckerApplication::handleAuthTokenResponse);
Thread.sleep(3600000);
};
}
private static Throwable handleAuthTokenError(Throwable e) {
LOGGER.error("Exception caught trying to process authentication token. ",e);
ContentCheckerApplication.handleAuthTokenResponse("");
return null;
}
private static void handleAuthTokenResponse(String newToken) {
LOGGER.info("Got status code!");
if (!newToken.isEmpty()) {
LOGGER.info("Auth token is: " + newToken);
} else {
LOGGER.info("Unable to authenticate successfully!");
}
System.exit(0);
}
}
import org.slf4j.Logger;
导入org.slf4j.LoggerFactory;
导入org.springframework.boot.CommandLineRunner;
导入org.springframework.boot.SpringApplication;
导入org.springframework.boot.WebApplicationType;
导入org.springframework.boot.autoconfigure.springboot应用程序;
导入org.springframework.context.annotation.Bean;
导入org.springframework.http.HttpStatus;
导入org.springframework.http.client.reactive.ReactorClientHttpConnector;
导入org.springframework.util.LinkedMultiValueMap;
导入org.springframework.web.reactive.function.BodyInserters;
导入org.springframework.web.reactive.function.client.ExchangeFunction;
导入org.springframework.web.reactive.function.client.ExchangeFunctions;
导入org.springframework.web.reactive.function.client.WebClient;
导入reactor.core.publisher.Mono;
@SpringBoot应用程序
公共类ContentCheckerApplication{
私有静态最终记录器Logger=LoggerFactory.getLogger(ContentCheckerApplication.class);
私有ExchangeFunction exchange=ExchangeFunctions.create(新建ReactorClient TTPConnector());
公共静态void main(字符串[]args){
SpringApplication app=新的SpringApplication(ContentCheckerApplication.class);
//防止SpringBoot启动web服务器
app.setWebApplicationType(WebApplicationType.NONE);
应用程序运行(args);
}
@豆子
公共命令行运行程序myCommandLineRunner(){
返回参数->{
//改变一些棘手的默认设置
ReactorClientHttpConnector连接器=新的ReactorClientHttpConnector(
选项->选项.option(ChannelOption.CONNECT\u TIMEOUT\u MILLIS,2000)
.压缩(真)
.AfterNettyContact(ctx->{
addHandlerLast(新的ReadTimeoutHandler(1500,TimeUnit.ms));
}));
LinkedMultiValueMap formData=新LinkedMultiValueMap();
添加(“用户名”,参数[2]);
添加(“密码”,参数[3]);
WebClient WebClient=WebClient.builder().clientConnector(connector.build();
Mono-tokenResult=webClient.post()
.uri(args[0]+“/api/token”)
.body(BodyInserters.fromFormData(formData))
.exchange()
.OneErrorMap(ContentCheckerApplication::handleAuthTokenError)
.map(响应->{
if(HttpStatus.OK.equals(response.statusCode())){