总是返回 Mono 和 Flux 错误 returns 500
Returning Mono and Flux error always returns 500
我仍在尝试了解 WebFlux 异常是如何工作的,据我所知,当 return 在 Flux 或 Mono 中访问一个对象时,消费者应该收到从服务器。
但是,例如,当我 return 在 Mono 中出现 HTTPException 401 时,我在消费者中收到的响应主体与我发送的响应主体不同,我读取了 500 内部服务器错误而不是 401。
这是一个简单的控制器class我为这个问题制作的
package com.example.demo;
import javax.xml.ws.http.HTTPException;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
@RestController
public class Controller {
@RequestMapping(
path="/getExceptionMono",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
public Mono<String> getException(){
return Mono.error(new HTTPException(401));
}
}
这是消费者:
package com.example.demo;
import org.springframework.boot.CommandLineRunner;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.WebClient;
@Component
public class ReactiveDemoConsumer implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
String url = "http://localhost:8080/getExceptionMono";
WebClient.create(url)
.get()
.accept(MediaType.APPLICATION_JSON)
.retrieve()
.bodyToMono(String.class)
.subscribe(value -> System.err.println("Received String: " + value),
err -> System.err.println("Received error " + err));
}
}
这是消费者的控制台日志
Received error org.springframework.web.reactive.function.client.WebClientResponseException$InternalServerError: 500 Internal Server Error from GET http://localhost:8080/getExceptionMono
如何传递我的异常,以便消费者看到我在 Mono 中传递的原始异常?
希望我的问题很清楚,提前致谢
这不是 return 来自应用程序的 4xx 响应的正确方法。
应用程序中抛出的任何类型的异常都将被 WebClientResponseException 包装并在客户端作为 500 内部服务器错误接收。
改变它的一种方法是在你的控制器中有一个异常处理程序,如下所示:
@ExceptionHandler({UnsupportedMediaTypeException.class})
public ResponseEntity<String> exceptionHandler(Exception ex) {
return ResponseEntity.badRequest().body(ex.getMessage());
}
另一种方法是在您的代码中使用全局异常处理程序:
(这里的 Ex1 类似于 HTTPException)
@Component
public class GlobalExceptionHandler implements ErrorWebExceptionHandler {
@Override
public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
ServerHttpResponse httpResponse = exchange.getResponse();
setResponseStatus(httpResponse, ex);
return httpResponse.writeWith(Mono.fromSupplier(() -> {
DataBufferFactory bufferFactory = httpResponse.bufferFactory();
try {
//Not displaying any error msg to client for internal server error
String errMsgToSend = (httpResponse.getStatusCode() == HttpStatus.INTERNAL_SERVER_ERROR) ? "" : ex.getMessage();
return bufferFactory.wrap(new ObjectMapper().writeValueAsBytes(errMsgToSend));
} catch (JsonProcessingException e) {
return bufferFactory.wrap(new byte[0]);
}
}));
}
private void setResponseStatus(ServerHttpResponse httpResponse, Throwable ex) {
if (ex instanceof Ex1 || ex instanceof Ex2 || ex instanceof Ex3) {
httpResponse.setStatusCode(HttpStatus.BAD_REQUEST);
} else {
httpResponse.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
}
或者你可以像这样重写你的控制器:
@RequestMapping(
path="/getExceptionMono",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
public Mono<ResponseEntity> getException(){
return Mono.just(ResponseEntity.badRequest().build());
}
}
然后在webclient代码中,你可以这样做:
webClient
.get()
.uri("/some/url")
.exchange()
.flatMap(clientResponse -> {
if (clientResponse.statusCode().is5xxServerError()) {
//do something and return some mono
}
else if(clientResponse.statusCode().is4xxClientError()) {
//do something and return some mono
}
else {
//do something and return some mono
}
});
我仍在尝试了解 WebFlux 异常是如何工作的,据我所知,当 return 在 Flux 或 Mono 中访问一个对象时,消费者应该收到从服务器。
但是,例如,当我 return 在 Mono 中出现 HTTPException 401 时,我在消费者中收到的响应主体与我发送的响应主体不同,我读取了 500 内部服务器错误而不是 401。
这是一个简单的控制器class我为这个问题制作的
package com.example.demo;
import javax.xml.ws.http.HTTPException;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
@RestController
public class Controller {
@RequestMapping(
path="/getExceptionMono",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
public Mono<String> getException(){
return Mono.error(new HTTPException(401));
}
}
这是消费者:
package com.example.demo;
import org.springframework.boot.CommandLineRunner;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.WebClient;
@Component
public class ReactiveDemoConsumer implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
String url = "http://localhost:8080/getExceptionMono";
WebClient.create(url)
.get()
.accept(MediaType.APPLICATION_JSON)
.retrieve()
.bodyToMono(String.class)
.subscribe(value -> System.err.println("Received String: " + value),
err -> System.err.println("Received error " + err));
}
}
这是消费者的控制台日志
Received error org.springframework.web.reactive.function.client.WebClientResponseException$InternalServerError: 500 Internal Server Error from GET http://localhost:8080/getExceptionMono
如何传递我的异常,以便消费者看到我在 Mono 中传递的原始异常? 希望我的问题很清楚,提前致谢
这不是 return 来自应用程序的 4xx 响应的正确方法。 应用程序中抛出的任何类型的异常都将被 WebClientResponseException 包装并在客户端作为 500 内部服务器错误接收。
改变它的一种方法是在你的控制器中有一个异常处理程序,如下所示:
@ExceptionHandler({UnsupportedMediaTypeException.class})
public ResponseEntity<String> exceptionHandler(Exception ex) {
return ResponseEntity.badRequest().body(ex.getMessage());
}
另一种方法是在您的代码中使用全局异常处理程序: (这里的 Ex1 类似于 HTTPException)
@Component
public class GlobalExceptionHandler implements ErrorWebExceptionHandler {
@Override
public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
ServerHttpResponse httpResponse = exchange.getResponse();
setResponseStatus(httpResponse, ex);
return httpResponse.writeWith(Mono.fromSupplier(() -> {
DataBufferFactory bufferFactory = httpResponse.bufferFactory();
try {
//Not displaying any error msg to client for internal server error
String errMsgToSend = (httpResponse.getStatusCode() == HttpStatus.INTERNAL_SERVER_ERROR) ? "" : ex.getMessage();
return bufferFactory.wrap(new ObjectMapper().writeValueAsBytes(errMsgToSend));
} catch (JsonProcessingException e) {
return bufferFactory.wrap(new byte[0]);
}
}));
}
private void setResponseStatus(ServerHttpResponse httpResponse, Throwable ex) {
if (ex instanceof Ex1 || ex instanceof Ex2 || ex instanceof Ex3) {
httpResponse.setStatusCode(HttpStatus.BAD_REQUEST);
} else {
httpResponse.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
}
或者你可以像这样重写你的控制器:
@RequestMapping(
path="/getExceptionMono",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
public Mono<ResponseEntity> getException(){
return Mono.just(ResponseEntity.badRequest().build());
}
}
然后在webclient代码中,你可以这样做:
webClient
.get()
.uri("/some/url")
.exchange()
.flatMap(clientResponse -> {
if (clientResponse.statusCode().is5xxServerError()) {
//do something and return some mono
}
else if(clientResponse.statusCode().is4xxClientError()) {
//do something and return some mono
}
else {
//do something and return some mono
}
});