我正在为我的
Webflux
服务中的以下端点编写集成测试
@GetMapping
public Mono<ResponseEntity<List<UserWebModel>>> getUsers() {
Flux<User> users = loadUserService.getusers(getUserIdFromToken());
return users.collectList()
.map(userList -> ResponseEntity.ok(userMapper.map(userList)))
.switchIfEmpty(Mono.just(ResponseEntity.status(HttpStatus.NOT_FOUND).build()));
}
当我在本地启动并测试服务时,此端点工作正常,但在我的集成测试中,我得到了
UnsupportedOperationException
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@AutoConfigureWebTestClient
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class UserIntegrationTest {
@Autowired
private WebTestClient webTestClient;
@Autowired
private UserRepository userRepository;
@BeforeAll
void setup() {
userRepository.saveAll(createMockUsers()).subscribe();
}
@AfterAll()
void cleanup() {
userRepository.deleteAll().subscribe();
}
@Test
void test_getUsers() {
initWiremockStubs();
this.webTestClient
.mutateWith(mockJwt().jwt(jwt -> jwt.claim("userid", "12345")))
.get()
.uri("/users")
.exchange()
.expectStatus().isOk();
}
异常
[ERROR] [] o.s.w.s.a.HttpWebHandlerAdapter - [4024b710] Error [java.lang.UnsupportedOperationException] for HTTP GET "/users", but ServerHttpResponse already committed (200 OK)
Error occurred after response was completed: OK(200 OK)[Vary:"Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers", Content-Type:"application/json", Content-Length:"2", Cache-Control:"no-cache, no-store, max-age=0, must-revalidate", Pragma:"no-cache", Expires:"0", X-Content-Type-Options:"nosniff", X-Frame-Options:"DENY", X-XSS-Protection:"0", Referrer-Policy:"no-referrer"]
org.springframework.web.reactive.function.client.WebClientRequestException: Error occurred after response was completed: OK(200 OK)[Vary:"Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers", Content-Type:"application/json", Content-Length:"2", Cache-Control:"no-cache, no-store, max-age=0, must-revalidate", Pragma:"no-cache", Expires:"0", X-Content-Type-Options:"nosniff", X-Frame-Options:"DENY", X-XSS-Protection:"0", Referrer-Policy:"no-referrer"]
at app//org.springframework.web.reactive.function.client.ExchangeFunctions$DefaultExchangeFunction.lambda$wrapException$9(ExchangeFunctions.java:136)
... 258 more
Caused by: java.lang.UnsupportedOperationException
at org.springframework.http.ReadOnlyHttpHeaders.set(ReadOnlyHttpHeaders.java:108)
在调试时我发现,
EncoderHttpMessageWriter
正在尝试将ContentLength
写入ReadOnlyHttpHeaders
,这会导致UnsupportedOperationException
。
if (inputStream instanceof Mono) {
return body
.singleOrEmpty()
.switchIfEmpty(Mono.defer(() -> {
message.getHeaders().setContentLength(0);
return message.setComplete().then(Mono.empty());
}))
.flatMap(buffer -> {
Hints.touchDataBuffer(buffer, hints, logger);
message.getHeaders().setContentLength(buffer.readableByteCount()); // <--
return message.writeWith(Mono.just(buffer)
.doOnDiscard(DataBuffer.class, DataBufferUtils::release));
})
.doOnDiscard(DataBuffer.class, DataBufferUtils::release);
}
当我删除端点中的响应正文时,测试有效。这里会出现什么问题?
可能有点晚了,但我想我分享一下。
我在 Spring WebFlux 应用程序中使用自定义
UnsupportedOperationException
时遇到了 OrderedWebFilter
。此问题是由于在提交响应后尝试修改 ReadOnlyHttpHeaders 引起的,由过滤器内的反应式流操作触发。
我有我的代码:
override fun filter(exchange: ServerWebExchange, chain: WebFilterChain): Mono<Void> {
val filter = chain.filter(exchange)
return securityHandler
.token()
.flatMap { successHandler.onAuthenticationSuccess(WebFilterExchange(exchange, chain), it) }
.then(filter)
.switchIfEmpty { filter }
}
我注意到
chain.filter(exchange)
中有一个额外的 switchIfEmpty
电话。
我还添加了
chain.filter(exchange)
电话检查。
最终代码是:
val differ = Mono.defer {
if (exchange.response.isCommitted) {
Mono.empty()
} else
chain.filter(exchange)
}
return securityHandler
.token()
.flatMap { successHandler.onAuthenticationSuccess(WebFilterExchange(exchange, chain), it) }
.then(differ)