无法使用 TestRestTemplate 测试请求参数中的文字“+”

问题描述 投票:0回答:1

在基于 Spring Boot 2.0.1 的微服务中,我有一个

GET
Rest 控制器,它采用编码为 ISO 字符串(缩短)的 fromDate 和 toDate:

@GetMapping(value = "/range")
public ResponseEntity<MyDTO> getDateRange(
        @RequestParam
        @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
                ZonedDateTime fromDate,
        @RequestParam
        @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
                ZonedDateTime toDate) {

    if (fromDate.isAfter(toDate) || fromDate.isEqual(toDate)) {
        return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
    }

    return new ResponseEntity<>(HttpStatus.OK);
}

因此请求应该类似于(完全 URL 编码):

http://localhost:8080/range/?fromDate=2015-05-31T03%3A00%3A00.000%2B04%3A00&toDate=2015-05-31T03%3A30%3A00.000%2B04%3A00

或者仅使用

+
转义:

http://localhost:8080/range/?fromDate=2015-05-31T03:00:00.000%2B04:00&toDate=2015-05-31T03:30:00.000%2B04:00

仅供参考,未进行 URI 编码的字符串为:

http://localhost:8080/range/?fromDate=2015-05-31T03:00:00.000+04:00&toDate=2015-05-31T03:30:00.000+04:00
- 这不起作用。

当我通过 Postman 执行

GETs
或通过在 Spring Boot 中使用
MockMvc
进行测试时,这个休息控制器工作得很好。但为了完整性和我自己的理解,我还想通过
TestRestTemplate
进行测试。然而,在参数中使用
+
是有问题的。但我不明白为什么。

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@RunWith(SpringRunner.class)
public class IntegrationTests {

    @Autowired
    private TestRestTemplate restTemplate;

    @Test
    public void test_get_in_range() throws Exception {
//        String uri = "/range?fromDate={fromDate}&toDate={toDate}";
//
//        Map<String, String> uriParams = new HashMap<>();
//        uriParams.put("fromDate", "2015-05-31T03:00:00.000+04:00");
//        uriParams.put("toDate", "2015-05-31T19:00:00.000+04:00");

        UriComponents uriComponents = UriComponentsBuilder
            .fromPath("/range")
            .queryParam("fromDate", "2015-05-31T03:00:00.000+04:00")
            .queryParam("toDate", "2015-05-31T19:00:00.000+04:00").build();
// Also tried with manually replacing + with %2B
// Also tried manually encoding the string

        ResponseEntity<String> getResponseEntity = restTemplate.withBasicAuth("cameraUser", "change_me")
                .getForEntity(uriComponents.toUriString(), String.class);
    }
}

服务器的结果是

Failed to convert from type [java.lang.String] to type [@org.springframework.web.bind.annotation.RequestParam @org.springframework.format.annotation.DateTimeFormat java.time.ZonedDateTime] for value '2015-05-31T03:00:00.000 04:00'; nested exception is java.lang.IllegalArgumentException: Parse attempt failed for value [2015-05-31T03:00:00.000 04:00]
字符串中的
+
似乎被空格替换了,当我执行来自 Postman 的未编码的
GET
请求时,也会发生这种情况。

在测试中将

+
替换为
%2B
会产生:

Failed to convert from type [java.lang.String] to type [@org.springframework.web.bind.annotation.RequestParam @org.springframework.format.annotation.DateTimeFormat java.time.ZonedDateTime] for value '2015-05-31T03:00:00.000%2B04:00'; nested exception is java.lang.IllegalArgumentException: Parse attempt failed for value [2015-05-31T03:00:00.000%2B04:00]

有人知道为什么吗?我怀疑它在某种程度上与自动配置有关,并且在测试模式下没有使用与默认执行相同的过滤器/转换器(术语不清楚)。我没有注册额外的转换器,并且 100% 依赖 Spring Boot 自动配置。

编辑:我创建了一个示例应用程序来显示问题here

java spring spring-mvc spring-boot junit
1个回答
0
投票

编码可能很棘手,因为某些字符在 URI 的不同部分可能是合法的。在这里,“+”字符在查询参数中是合法的,从框架的角度来看,它并不明显是客户端所期望的。

Spring Framework 文档中有一个关于 URI 编码的专门部分解释了这一切。将建议应用于您的测试将使测试通过:

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class UriexpandApplicationTests {

    @Autowired
    private TestRestTemplate restTemplate;

    @Test
    void test_get_in_range() {
        URI uri = UriComponentsBuilder
                .fromPath("/range")
                .queryParam("fromDate", "{fromDate}")
                .queryParam("toDate", "{toDate}")
                .build("2015-05-31T03:00:00.000+04:00", "2015-05-31T19:00:00.000+04:00");

        ResponseEntity<String> getResponseEntity = restTemplate
                .getForEntity(uri, String.class);
        assertThat(getResponseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
    }

}
© www.soinside.com 2019 - 2024. All rights reserved.