You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TestRestTemplate设置ENABLE_REDIRECTS后仍不执行重定向的问题排查

Spring PRG模式集成测试中TestRestTemplate重定向与Flash属性问题解决方案

问题背景

基于Spring框架采用PRG(Post-Redirect-Get)模式开发控制器,结合RedirectView、RedirectAttributes和addFlashAttributes实现功能,手动浏览器访问时重定向逻辑正常。但使用TestRestTemplate进行全链路集成测试时,即便设置了HttpClientOption.ENABLE_REDIRECTS,调用postForEntity仍仅返回302状态码和重定向地址,无法自动完成重定向,也无法获取Post控制器中的Flash属性,导致后续GET请求无法复用这些属性。已知MockMVC可获取Flash属性,但无法满足全链路测试需求,需解决以下问题:

  1. ENABLE_REDIRECTS配置是否有误?
  2. 有无其他配置重定向的方式(例如在postForEntity的HttpRequest中配置)?
  3. 如何让TestRestTemplate自动完成重定向?
  4. 若无法实现自动重定向,能否配置TestRestTemplate返回Flash属性,供后续针对重定向地址的GET请求使用?

解决方案

1. 关于ENABLE_REDIRECTS配置的有效性

你的配置方式本身没有错误,但TestRestTemplate的ENABLE_REDIRECTS仅对标准GET请求的重定向生效。根据HTTP规范,Post请求返回302时,客户端默认不会自动跳转(需主动发起GET请求),因此该选项无法处理Post转Get的PRG场景重定向,并非配置错误。

2. 其他重定向配置方式

可以通过自定义RestTemplate的ClientHttpRequestFactory,配置宽松重定向策略,支持Post转Get的重定向逻辑:

// 构建支持Post转Get重定向的HttpClient
CloseableHttpClient httpClient = HttpClientBuilder.create()
        .setRedirectStrategy(new LaxRedirectStrategy()) // 宽松策略自动处理302/303重定向
        .build();
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);

// 用自定义工厂构建TestRestTemplate
RestTemplateBuilder rtb = new RestTemplateBuilder()
        .rootUri("http://localhost:7777")
        .requestFactory(() -> factory);
TestRestTemplate trt = new TestRestTemplate(rtb);

LaxRedirectStrategy会自动跟进重定向,无论原请求方法是什么,都会转为GET请求访问目标地址。

3. 让TestRestTemplate自动完成重定向

使用上述自定义LaxRedirectStrategy配置后,postForEntity会自动跟进重定向,返回最终GET请求的响应结果。需注意:

  • 重定向后的响应是目标GET接口(如/view)的返回内容
  • Flash属性存储在Session中,测试时需使用同一个TestRestTemplate实例,或手动维护会话Cookie(JSESSIONID)以保持上下文

修改后的测试代码示例:

@Test
@Order(0020)
void givenTestMyentityWhenSubmitThenExpectedViewDataReturned() throws Exception {
    Myentity tempMyentity = testData.getGoodTestData().get("test-myentity-001");

    // 配置支持重定向的HttpClient
    CloseableHttpClient httpClient = HttpClientBuilder.create()
            .setRedirectStrategy(new LaxRedirectStrategy())
            .build();
    HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);

    RestTemplateBuilder rtb = new RestTemplateBuilder()
            .rootUri("http://localhost:7777")
            .requestFactory(() -> factory);
    TestRestTemplate trt = new TestRestTemplate(rtb);

    // 自动跟进重定向,直接返回/view的响应
    ResponseEntity<String> responseView = trt.postForEntity("/submit",
            HttpRequester.makeMyEntityHttpRequest(tempMyentity), String.class);

    assertEquals(HttpStatus.OK, responseView.getStatusCode());
    // 断言视图内容,比如包含Flash属性对应的成功提示
    assertTrue(responseView.getBody().contains("操作成功"));
}

4. 手动处理重定向时获取Flash属性

若不需要自动重定向,可通过维护会话Cookie的方式,让后续GET请求读取到Flash属性:

  1. 发送Post请求,获取302响应及会话Cookie(JSESSIONID)
  2. 携带该Cookie发送GET请求到重定向地址,此时Controller可读取到Session中的Flash属性

示例代码:

@Test
@Order(0020)
void givenTestMyentityWhenSubmitThenUseFlashAttributesInGet() throws Exception {
    Myentity tempMyentity = testData.getGoodTestData().get("test-myentity-001");

    TestRestTemplate trt = new TestRestTemplate(new RestTemplateBuilder().rootUri("http://localhost:7777"));

    // 发送Post请求,获取302响应
    ResponseEntity<String> responseSubmit = trt.postForEntity("/submit",
            HttpRequester.makeMyEntityHttpRequest(tempMyentity), String.class);
    assertEquals(HttpStatus.FOUND, responseSubmit.getStatusCode());
    String location = responseSubmit.getHeaders().getLocation().toString();

    // 提取会话Cookie
    List<String> cookies = responseSubmit.getHeaders().get(HttpHeaders.SET_COOKIE);
    String sessionCookie = cookies.stream()
            .filter(c -> c.startsWith("JSESSIONID="))
            .findFirst()
            .orElseThrow(() -> new IllegalStateException("未获取到会话Cookie"));

    // 构造携带Cookie的GET请求
    HttpHeaders headers = new HttpHeaders();
    headers.add(HttpHeaders.COOKIE, sessionCookie);
    HttpEntity<Void> getRequest = new HttpEntity<>(headers);

    // 发送GET请求,读取Flash属性
    ResponseEntity<String> responseView = trt.exchange(location, HttpMethod.GET, getRequest, String.class);
    assertEquals(HttpStatus.OK, responseView.getStatusCode());
    // 断言视图中包含Flash属性对应的内容
}

额外说明

  • 全链路测试中,TestRestTemplate默认无状态,每次请求新建会话,需复用实例或手动传递Cookie保持会话上下文
  • LaxRedirectStrategy依赖Apache HttpClient,需确保项目引入org.apache.httpcomponents:httpclient依赖

内容的提问来源于stack exchange,提问作者tlarson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 05:30:14