簡體   English   中英

使用 Spring webflux 和 WebTestClient 獲取請求屬性

[英]Get request attribute with Spring webflux and WebTestClient

我不能綁定的屬性我是從一個設置WebTestClientRestController使用Spring WebFlux時。

我嘗試了我能想到的兩種方法。

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

無法處理請求 [GET /attributes/annotation]:響應狀態 400,原因是“缺少字符串類型的請求屬性‘attribute’”

然后我嘗試使用 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,它從(解碼的)標頭值設置一些屬性,我想獲取這些屬性。

在服務器端和客戶端,請求屬性都應視為類似於Map的數據結構,可用於在客戶端/服務器內傳輸信息(用於過濾器,編解碼器等)。

該信息不會通過網絡發送。

如果要將信息從客戶端發送到服務器,則應查看請求參數或請求主體本身。

我在之前使用 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);
        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM