У меня простой эхо-контроллер
@RestController
public class EchoController {
@GetMapping(path = "/param", produces = MediaType.TEXT_PLAIN_VALUE)
String echoParam(@RequestParam("p") String paramValue) {
return paramValue;
}
@GetMapping(path = "/path-variable/{val}", produces = MediaType.TEXT_PLAIN_VALUE)
String echoPathVariable(@PathVariable("val") String val) {
return val;
}
}
Один из его методов повторяет значение параметра, который был представлен; вторая делает то же самое со значением, предоставленным через URI.
У меня есть следующие тесты:
@Autowired
private WebTestClient webTestClient;
@Test
public void rawPlus_inQueryParam() {
String value = "1+1";
String response = getValueEchoedThroughQueryParam(value);
assertThat(response, is(equalTo(value)));
}
@Test
public void urlencodedPlus_inQueryParam() {
String value = "1%2B1";
String response = getValueEchoedThroughQueryParam(value);
assertThat(response, is(equalTo(value)));
}
private String getValueEchoedThroughQueryParam(String value) {
return webTestClient.get()
.uri(builder -> {
return builder
.path("/param")
.queryParam("p", value)
.build();
})
.exchange()
.expectStatus().is2xxSuccessful()
.expectBody(String.class)
.returnResult()
.getResponseBody();
}
Оба теста просто отправляют строку через параметр запроса, читают ответ и утверждают, что содержимое отображено правильно.
Первый тест не пройден:
java.lang.AssertionError:
Expected: is "1+1"
but: was "1 1"
Второй тест пройден.
Похоже, что во втором тесте WebTestClient
url-кодирует значение (фактически, это просто url-кодирование символа процента), затем веб-сервер url-декодирует его, и все в порядке. Но в первом тесте клиент не url-кодирует символ плюс, а сервер url-декодирует его, следовательно, он получает символ пробела.
Это выглядит как несоответствие. Я сомневаюсь, что мог бы сделать что-то глупое, чтобы вызвать это, потому что все работает в режиме по умолчанию; фактически, контроллер, который я здесь показываю, является практически единственным кодом, который имеет приложение (сам класс приложения является стандартным, я не трогал его после того, как он был сгенерирован).
Просто для сравнения: при передаче тех же данных в URI все работает правильно. Сданы следующие тесты:
@Test
public void rawPlus_inPathVariable() {
String value = "1+1";
String response = getValueEchoedThroughPathVariable(value);
assertThat(response, is(equalTo(value)));
}
@Test
public void urlencodedPlus_inPathVariable() {
String value = "1%2B1";
String response = getValueEchoedThroughPathVariable(value);
assertThat(response, is(equalTo(value)));
}
private String getValueEchoedThroughPathVariable(String value) {
return webTestClient.get()
.uri("/path-variable/" + value)
.exchange()
.expectStatus().is2xxSuccessful()
.expectBody(String.class)
.returnResult()
.getResponseBody();
}
Вопросы :
- Это ошибка в Spring Boot (или одном из компонентов, которые он использует)?
- Если нет, я что-то не так сделал?
- И практический вопрос: как передать значение параметра запроса, содержащее символ плюс, в тестах, написанных для
WebTestClient
? Если я не кодирую его вручную, он будет декодирован URL-адресом веб-сервером; если я это сделаю, он получит URL-кодированный второй раз, поэтому сервер получит (после URL-декодирования) версию с URL-декодированием.
Версия Spring Boot 2.1.4.RELEASE
(самая последняя на момент написания).
POM следует:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.4.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>springboot-plus-in-query-string</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-plus-in-query-string</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Проект доступен на GitHub: https://github.com/rpuch/springboot-plus-in-query-string
Просто запустите тесты (mvn clean test
).