无法在 URL 中记录 JSON
Documenting JSON in URL not possible
在我的 Rest API 中,应该可以检索边界框内的数据。因为边界框有四个坐标,所以我想以这种方式设计 GET 请求,使它们接受边界框 JSON。因此,我需要能够将 JSON 字符串作为 URL 参数发送和记录。
测试本身有效,但我无法使用 Spring RestDocs (1.0.0.RC1) 记录这些请求。我用更简单的方法重现了这个问题。见下文:
@Test public void ping_username() throws Exception
{
String query = "name={\"user\":\"Müller\"}";
String encodedQuery = URLEncoder.encode(query, "UTF-8");
mockMvc.perform(get(URI.create("/ping?" + encodedQuery)))
.andExpect(status().isOk())
.andDo(document("ping_username"));
}
当我删除 .andDo(document("ping_username"))
时,测试通过。
堆栈跟踪:
java.lang.IllegalArgumentException: Illegal character in query at index 32: http://localhost:8080/ping?name={"user":"Müller"}
at java.net.URI.create(URI.java:852)
at org.springframework.restdocs.mockmvc.MockMvcOperationRequestFactory.createOperationRequest(MockMvcOperationRequestFactory.java:79)
at org.springframework.restdocs.mockmvc.RestDocumentationResultHandler.handle(RestDocumentationResultHandler.java:93)
at org.springframework.test.web.servlet.MockMvc.andDo(MockMvc.java:158)
at application.rest.RestApiTest.ping_username(RestApiTest.java:65)
在我收到对 URL 进行编码的建议后,我尝试了它,但问题仍然存在。
在我的测试中用于创建 URI 的字符串现在是 /ping?name%3D%7B%22user%22%3A%22M%C3%BCller%22%7D
。
我检查了堆栈跟踪中出现的 class MockMvcOperationRequestFactory
,并在第 79 行执行了以下代码:
URI.create(getRequestUri(mockRequest)
+ (StringUtils.hasText(queryString) ? "?" + queryString : ""))
这里的问题是使用了未编码的字符串(在我的例子中 http://localhost:8080/ping?name={"user":"Müller"}
)并且 URI 创建失败。
备注:
Andy Wilkinson 的回答是问题的解决方案。虽然我认为 David Sinfield 是正确的,并且 JSONs 应该避免在 URL 中以保持简单。对于我的边界框,我将使用逗号分隔的字符串,因为它在 WMS 1.1 中使用:BBOX=x1,y1,x2,y2
问题是 URI 必须编码为 ACII。并且 ü
不是有效的 ASCII 字符,因此必须在 url 中使用 %
进行转义。
如果您正在使用 Tomcat,您可以在 server.xml
的 Connector
元素中使用 URIEncoding="UTF-8"
,将 UTF-8 转义配置为默认值。如果这样做,ü
将自动转换为 %C3%BC
,这是 \uC3BC
Unicode 代码点(代表 ü
)的 ASCII 表示。
编辑: 看来我没漏到具体的错误点,但还是一样的错误。 Curly 大括号在 URI 中无效。根据 RFC 3986,仅接受以下字符:
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~:/?#[]@!$&'()*+,;=%
所以这些也必须转义。
您没有提到您正在使用的 Spring REST Docs 的版本,但我猜想问题出在 URIUtil
上。我无法确定,因为我看不到 URIUtil
来自哪里。
无论如何,使用 JDK 的 URLEncoder
对我来说适用于 Spring REST Docs 1.0.0.RC1:
String query = "name={\"user\":\"Müller\"}";
String encodedQuery = URLEncoder.encode(query, "UTF-8");
mockMvc.perform(get(URI.create("/baz?" + encodedQuery)))
.andExpect(status().isOk())
.andDo(document("ping_username"));
然后你可以在服务器端使用URLDecoder.decode
得到原来的JSON:
URLDecoder.decode(request.getQueryString(), "UTF-8")
在我的 Rest API 中,应该可以检索边界框内的数据。因为边界框有四个坐标,所以我想以这种方式设计 GET 请求,使它们接受边界框 JSON。因此,我需要能够将 JSON 字符串作为 URL 参数发送和记录。
测试本身有效,但我无法使用 Spring RestDocs (1.0.0.RC1) 记录这些请求。我用更简单的方法重现了这个问题。见下文:
@Test public void ping_username() throws Exception
{
String query = "name={\"user\":\"Müller\"}";
String encodedQuery = URLEncoder.encode(query, "UTF-8");
mockMvc.perform(get(URI.create("/ping?" + encodedQuery)))
.andExpect(status().isOk())
.andDo(document("ping_username"));
}
当我删除 .andDo(document("ping_username"))
时,测试通过。
堆栈跟踪:
java.lang.IllegalArgumentException: Illegal character in query at index 32: http://localhost:8080/ping?name={"user":"Müller"}
at java.net.URI.create(URI.java:852)
at org.springframework.restdocs.mockmvc.MockMvcOperationRequestFactory.createOperationRequest(MockMvcOperationRequestFactory.java:79)
at org.springframework.restdocs.mockmvc.RestDocumentationResultHandler.handle(RestDocumentationResultHandler.java:93)
at org.springframework.test.web.servlet.MockMvc.andDo(MockMvc.java:158)
at application.rest.RestApiTest.ping_username(RestApiTest.java:65)
在我收到对 URL 进行编码的建议后,我尝试了它,但问题仍然存在。
在我的测试中用于创建 URI 的字符串现在是 /ping?name%3D%7B%22user%22%3A%22M%C3%BCller%22%7D
。
我检查了堆栈跟踪中出现的 class MockMvcOperationRequestFactory
,并在第 79 行执行了以下代码:
URI.create(getRequestUri(mockRequest)
+ (StringUtils.hasText(queryString) ? "?" + queryString : ""))
这里的问题是使用了未编码的字符串(在我的例子中 http://localhost:8080/ping?name={"user":"Müller"}
)并且 URI 创建失败。
备注:
Andy Wilkinson 的回答是问题的解决方案。虽然我认为 David Sinfield 是正确的,并且 JSONs 应该避免在 URL 中以保持简单。对于我的边界框,我将使用逗号分隔的字符串,因为它在 WMS 1.1 中使用:BBOX=x1,y1,x2,y2
问题是 URI 必须编码为 ACII。并且 ü
不是有效的 ASCII 字符,因此必须在 url 中使用 %
进行转义。
如果您正在使用 Tomcat,您可以在 server.xml
的 Connector
元素中使用 URIEncoding="UTF-8"
,将 UTF-8 转义配置为默认值。如果这样做,ü
将自动转换为 %C3%BC
,这是 \uC3BC
Unicode 代码点(代表 ü
)的 ASCII 表示。
编辑: 看来我没漏到具体的错误点,但还是一样的错误。 Curly 大括号在 URI 中无效。根据 RFC 3986,仅接受以下字符:
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~:/?#[]@!$&'()*+,;=%
所以这些也必须转义。
您没有提到您正在使用的 Spring REST Docs 的版本,但我猜想问题出在 URIUtil
上。我无法确定,因为我看不到 URIUtil
来自哪里。
无论如何,使用 JDK 的 URLEncoder
对我来说适用于 Spring REST Docs 1.0.0.RC1:
String query = "name={\"user\":\"Müller\"}";
String encodedQuery = URLEncoder.encode(query, "UTF-8");
mockMvc.perform(get(URI.create("/baz?" + encodedQuery)))
.andExpect(status().isOk())
.andDo(document("ping_username"));
然后你可以在服务器端使用URLDecoder.decode
得到原来的JSON:
URLDecoder.decode(request.getQueryString(), "UTF-8")