首页 文章

如何使用Spring WebFlux返回404

提问于
浏览
2

我有一个像这样的控制器(在Kotlin):

@RestController
@RequestMapping("/")
class CustomerController (private val service: CustomerService) {
    @GetMapping("/{id}")
    fun findById(@PathVariable id: String,
                 @RequestHeader(value = IF_NONE_MATCH) versionHeader: String?): Mono<HttpEntity<KundeResource>> =
        return service.findById(id)
            .switchIfEmpty(Mono.error(NotFoundException()))
            .map {
                // ETag stuff ...
                ok().eTag("...").body(...)
            }
}

我想知道是否有更好的方法而不是抛出一个带有 @ResponseStatus(code = NOT_FOUND) 注释的异常

3 回答

  • 2

    当Spring 5稳定时,我想使用 RouteFunction 而不是@RestController . 定义HandlerFunction以处理请求,然后声明 RouteFunction 以将请求映射到HandlerFunction:

    public Mono<ServerResponse> get(ServerRequest req) {
        return this.posts
            .findById(req.pathVariable("id"))
            .flatMap((post) -> ServerResponse.ok().body(Mono.just(post), Post.class))
            .switchIfEmpty(ServerResponse.notFound().build());
    }
    

    检查完整的示例代码here .

    Kotlin版本,定义一个处理请求的函数,使用 RouteFunctionDSL 将传入的请求映射到HandlerFuncation:

    fun get(req: ServerRequest): Mono<ServerResponse> {
        return this.posts.findById(req.pathVariable("id"))
                .flatMap { post -> ok().body(Mono.just(post), Post::class.java) }
                .switchIfEmpty(notFound().build())
    }
    

    它可以是一个表达式,如:

    fun get(req: ServerRequest): Mono<ServerResponse> = this.posts.findById(req.pathVariable("id"))
                .flatMap { post -> ok().body(Mono.just(post), Post::class.java) }
                .switchIfEmpty(notFound().build())
    

    查看Kotlin DSL here的完整示例代码 .

    如果您更喜欢传统控制器来公开REST API,请尝试这种方法 .

    首先定义一个例外,例如 . PostNotFoundException . 然后把它扔进控制器 .

    @GetMapping(value = "/{id}") public Mono<Post> get(@PathVariable(value = "id") Long id) { return this.posts.findById(id).switchIfEmpty(Mono.error(new PostNotFoundException(id))); }

    定义 ExceptionHandler 来处理异常,并在 HttpHandler 中注册它 .

    @Profile("default")
    @Bean
    public NettyContext nettyContext(ApplicationContext context) {
        HttpHandler handler = WebHttpHandlerBuilder.applicationContext(context)
            .exceptionHandler(exceptionHandler())
            .build();
        ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(handler);
        HttpServer httpServer = HttpServer.create("localhost", this.port);
        return httpServer.newHandler(adapter).block();
    }
    
    @Bean
    public WebExceptionHandler exceptionHandler() {
        return (ServerWebExchange exchange, Throwable ex) -> {
            if (ex instanceof PostNotFoundException) {
                exchange.getResponse().setStatusCode(HttpStatus.NOT_FOUND);
                return exchange.getResponse().setComplete();
            }
            return Mono.error(ex);
        };
    }
    

    在这里查看complete codes . 对于Spring Boot用户,请检查this sample .

  • 0

    可以将方法的实现更改为,而不是抛出异常

    fun findById(@PathVariable id: String,
                 @RequestHeader(value = IF_NONE_MATCH) versionHeader: String?): Mono<ResponseEntity<KundeResource>> =
        return service.findById(id)
            .map {
                // ETag stuff ...
                ok().eTag("...").body(...)
            }
            .defaultIfEmpty(notFound().build())
    
  • 6

    您可以使用ResponseStatusException,只需扩展您的例外:

    public class YourLogicException extends ResponseStatusException {
    
    public YourLogicException(String message) {
        super(HttpStatus.BAD_REQUEST, message);
    }
    
    public YourLogicException(String message, Throwable cause) {
        super(HttpStatus.BAD_REQUEST, message, cause);
    }
    

    在服务中:

    public Mono<String> doLogic(Mono<YourContext> ctx) {
        return ctx.map(ctx -> doSomething(ctx));
    }
    
    private String doSomething(YourContext ctx) {
        try {
            // some logic
        } catch (Exception e) {
            throw new YourLogicException("Exception message", e);
        }
    }
    

    在那之后,你可以得到一个漂亮的信息:

    { "timestamp": 00000000, "path": "/endpoint", "status": 400, "error": "Bad Request", "message": "Exception message" }
    

相关问题