【问题标题】:Get request attribute with Spring webflux and WebTestClient使用 Spring webflux 和 WebTestClient 获取请求属性
【发布时间】:2018-07-24 16:08:11
【问题描述】:

在使用 Spring WebFlux 时,我无法将我设置的属性从 WebTestClient 绑定到 RestController

我尝试了我能想到的两种方法。

首先使用@RequestAttribute注解,我得到了:

无法处理请求 [GET /attributes/annotation]:响应状态 400,原因为“缺少字符串类型的请求属性‘属性’”

然后我尝试使用 ServerWebExchange 并且是 null

这是我的控制器:

@RestController
@RequestMapping("/attributes")
public class MyController {

    @GetMapping("/annotation")
    public Mono<String> getUsingAnnotation(@RequestAttribute("attribute") String attribute) {
        return Mono.just(attribute);
    }

    @GetMapping("/exchange")
    public Mono<String> getUsingExchange(ServerWebExchange exchange) {
        return Mono.just(exchange.getRequiredAttribute("attribute"));
    }
}

这是我失败的测试:

@RunWith(SpringRunner.class)
@SpringBootTest
public class MyControllerTest {

    @Autowired
    ApplicationContext context;

    WebTestClient webClient;

    @Before
    public void setup() {
        webClient = WebTestClient.bindToApplicationContext(context)
                .configureClient()
                .build();
    }

    @Test
    public void testGetAttributeUsingAnnotation() {
        webClient.get()
                .uri("/attributes/annotation")
                .attribute("attribute", "value")
                .exchange()
                .expectStatus()
                .isOk();
    }

    @Test
    public void testGetAttributeUsingExchange() {
        webClient.get()
                .uri("/attributes/exchange")
                .attribute("attribute", "value")
                .exchange()
                .expectStatus()
                .isOk();
    }

}

在我的真实应用程序中,我有一个 SecurityContextRepository,它从(解码的)标头值设置一些属性,我想获取这些属性。

【问题讨论】:

    标签: java spring-webflux


    【解决方案1】:

    无论是在服务器端还是客户端,请求属性都应该被视为类似于 Map 的数据结构,可用于在客户端/服务器内传输信息(用于过滤器、编解码器等)。

    该信息不会通过网络发送。

    如果您想将该信息从客户端发送到服务器,您应该查看请求参数或请求正文本身。

    【讨论】:

    • 感谢您的回答。我知道此属性是通过解码标头(JWT)在服务器端设置的,当我发送标头时,我可以使用ServerWebExchange 成功获取该属性。但是我想通过直接设置属性来简化我的测试,就像我在 webflux 之前对MockMvc 所做的那样,就像这样:mvc.perform(get(...).requestAttr("foo", "bar"))。而这过去工作得很好。
    【解决方案2】:

    我在以前使用 MockMvc 的测试中遇到了同样的问题,然后必须转换为使用 WebClient。像 @jcfandino 我期待 WebClient 上的 .attribute() 方法与 MockMvc 的 requestAttribute() 类似。

    我还没有发现.attribute() 的用途,但我通过添加自定义测试过滤器绕过了整个问题。我不确定这种方法是否正确,但由于这个问题没有得到解答,下面的方法可能对遇到同样问题的人有所帮助。

    @WebFluxTest(controllers = SomeController.class)
    @ComponentScan({ "com.path1", "com.path2" })
    class SomeControllerTest {
    
        // define a test filter emulating the server's filter (assuming there is one)
        private class AttributeFilter implements WebFilter {
    
            String attributeValue;
            
            public AttributeFilter(String filterAttributeValue) {
                attributeValue = filterAttributeValue;
            }
            
            @Override
            public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
                // add the desired attributes 
                exchange.getAttributes().put(SomeController.ATTR_NAME, attributeValue);   
                return chain.filter(exchange);
            }
        }
       
        // mock the service the controller is dependend on
        @MockBean
        AppService appService; 
    
        // define the test where the controller handles a get() operation 
        @Test
        void testMethod() {
            
            // mock the app service
            when(appService.executeService(anyString(), anyString())).thenAnswer(input -> {
                // ... return some dummy appData
            });
    
            var testClient= WebTestClient.bindToController(new SomeController(appService))                
                    .webFilter(new SomeControllerTest.AttributeFilter("someValue"))
                    .build();
    
            try {            
                var response = testClient
                    .get()               
                    .uri("someroute")
                    .accept(MediaType.APPLICATION_JSON)
                    .exchange()
                    .expectStatus().isOk()
                    .expectBody(AppData.class);                             
                    
            } catch (Exception e) {
                fail("exception caught in testMethod", e);
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2021-06-23
      • 2018-01-08
      • 2020-10-24
      • 2020-07-29
      • 2020-10-17
      • 2019-07-23
      • 2021-12-30
      • 1970-01-01
      • 2018-10-07
      相关资源
      最近更新 更多