【问题标题】:Spring WebFlux Route always returns 404Spring WebFlux Route 总是返回 404
【发布时间】:2020-02-03 10:15:19
【问题描述】:

我正在做一个简单的项目,它使用 Spring Boot 2 和使用 Kotlin 的 Spring WebFlux。 我为我的处理程序函数编写了测试(在其中我使用 Mockito 模拟了依赖项)。

但是,我的路由函数似乎没有触发处理程序,因为我的所有请求都返回 HTTP 404 NOT FOUND(即使路由是正确的)。

我查看了其他各种项目以了解这些测试应该如何编写(herehere),但问题仍然存在。

代码如下(也可以在GitHub上找到):

用户路由器测试

@ExtendWith(SpringExtension::class, MockitoExtension::class)
@Import(UserHandler::class)
@WebFluxTest
class UserRouterTest {

    @MockBean
    private lateinit var userService: UserService

    @Autowired
    private lateinit var userHandler: UserHandler

    @Test
    fun givenExistingCustomer_whenGetCustomerByID_thenCustomerFound() {
        val expectedCustomer = User("test", "test")
        val id = expectedCustomer.userID

        `when`(userService.getUserByID(id)).thenReturn(Optional.ofNullable(expectedCustomer))

        val router = UserRouter().userRoutes(userHandler)
        val client = WebTestClient.bindToRouterFunction(router).build()

        client.get()
                .uri("/users/$id")
                .accept(MediaType.ALL)
                .exchange()
                .expectStatus().isOk
                .expectHeader().contentType(MediaType.APPLICATION_JSON_UTF8)
                .expectBody(User::class.java)
    }
}

用户

@Entity
class User(var username : String, var password: String) {

    @Id
    val userID = UUID.randomUUID()
}

用户存储库

@Repository
interface UserRepository : JpaRepository<User, UUID>{
}

用户服务

@Service
class UserService(
        private val userRepository: UserRepository
) {
    fun getUserByID(id: UUID): Optional<User> {
        return Optional.of(
                try {
                    userRepository.getOne(id)
                } catch (e: EntityNotFoundException) {
                    User("test", "test")
                }
        )
    }

    fun addUser(user: User) {
        userRepository.save(user)
    }
}

用户处理程序

@Component
class UserHandler(
        private val userService: UserService
) {
    fun getUserWithID(request: ServerRequest): Mono<ServerResponse> {
        val id = try {
            UUID.fromString(request.pathVariable("userID"))
        } catch (e: IllegalArgumentException) {
            return ServerResponse.badRequest().syncBody("Invalid user id")
        }
        val user = userService.getUserByID(id).get()
        return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON_UTF8)
                .body(BodyInserters.fromObject(user))
    }
}

用户路由器

@Configuration
class UserRouter {
    @Bean
    fun userRoutes(userHandler: UserHandler) = router {
        contentType(MediaType.APPLICATION_JSON_UTF8).nest {
            GET("/users/{userID}", userHandler::getUserWithID)
            GET("") { ServerResponse.ok().build() }
        }
    }
}

编辑

要基于一个或多个查询参数的存在进行路由(无论它们的值如何),我们可以执行以下操作: 用户路由器

@Configuration
class UserRouter {
    @Bean
    fun userRoutes(userHandler: UserHandler) = router {

        GET("/users/{userID}", userHandler::getUserWithID)
        (GET("/users/")
                and queryParam("username") { true }
                and queryParam("password") { true }
                )
                .invoke(userHandler::getUsers)
    }
}

注意GET("/users/?username={username}", userHandler::getUsersWithUsername) 不起作用。

【问题讨论】:

    标签: spring-boot kotlin mockito spring-webflux


    【解决方案1】:

    路由器的配置方式 - contentType(MediaType.APPLICATION_JSON_UTF8).nest - 将仅匹配具有此内容类型的 请求,因此您必须删除 contentType 先决条件或更改测试以包含它

    client.get()
                    .uri("/users/$id")
                    .accept(MediaType.ALL)
                    .header("Content-Type", "application/json;charset=UTF-8")
                    .exchange()
                    .expectStatus().isOk
                    .expectHeader().contentType(MediaType.APPLICATION_JSON_UTF8)
                    .expectBody(User::class.java)
    

    【讨论】:

    • 谢谢,这行得通!我也试图让它与包含查询参数的 GET 请求一起工作。将路由GET("/users/?username={username}") { ServerResponse.ok().build() } 添加到我的UserRouter(并删除其他路由)并使用uri "/users/?username=${expectedCustomer.username}" 构建查询后,我再次得到404。你知道我在这里做错了什么吗?跨度>
    • 这条路由/users/?username=${expectedCustomer.username} 看起来不正确,它的构造应该没有尾随/ (RFC 3986 - tools.ietf.org/html/rfc3986#section-3) 至于路由器 GET 本身 - 我不是 webflux 路由器专家,但我相信您可以将端点定义为GET("/users", userHandler::getUsers)。从这里开始,您可以根据处理程序内部的查询参数实现一些逻辑,例如val userId = request.queryParam("id").orElseThrow { Exception("no id provided as query param") }
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-01-26
    • 1970-01-01
    • 2016-11-19
    • 2018-07-15
    • 2016-03-02
    • 2020-02-09
    • 2021-08-05
    相关资源
    最近更新 更多