控制器返回输入流 - 内容协商和媒体类型
Controller returning inputstream - content negotiation and media types
简介
我有一个关于 RestController 和 Test 的问题。
我有以下 PostMapping
:
@PostMapping(path = "/download/as/zip/{zipFileName}" )
@ResponseBody
public ResponseEntity<InputStreamResource> downloadDocumentZip(@RequestHeader(required=false,name="X-Application") String appName, @RequestBody ZipFileModel zipFileModel, @PathVariable("zipFileName") String zipFileName)
我有以下测试:
Response response = given(this.requestSpecification).port(port)
.filter(document("downloadAsZip",
preprocessRequest(prettyPrint()),
requestHeaders(headerWithName("X-Application").description("Owner application")),
pathParameters(parameterWithName("zipFileName").description("The name of the resulting zip file. Mostly not needed/optional.")))
)
.contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)
.header(new Header(HEADER, "themis"))
.body(jsonContent)
.when()
.post("/download/as/zip/{zipFileName}", "resultFile.zip");
这有效并返回 200。
第一个问题
现在我对测试中.contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)
的含义有点困惑。
Content-type 是返回响应中的 header。但是在这个测试中,它是在提出测试请求时被包含在内的吗? 或者在这种情况下是否表示我们在请求中发送 JSON body?
第二个问题
我知道我的控制器方法应该消耗 JSON 和 returns 字节。
因此,我做出以下更改:
@PostMapping(path = "/download/as/zip/{zipFileName}", 消耗 = MediaType.APPLICATION_JSON_VALUE)
目前有效。
然后我添加以下内容:
@PostMapping(path = "/download/as/zip/{zipFileName}", consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
失败了:
java.lang.AssertionError:
Expected :200
Actual :406
<Click to see difference>
所以我将测试更改为以下内容:
.contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)
.accept(MediaType.APPLICATION_OCTET_STREAM_VALUE)
这又一次失败了。
Expected :200
Actual :406
因此,即使客户端发出与控制器生成的信号相同的接受 header 信号,我们也会出现错误。
问题:
- 那么我们应该还是不应该在请求映射上有
produces=
?
- 为什么现在失败了?消费JSON和生产字节有冲突吗?还是测试中的
ContentType
?
问题在于,如果 URL 的结尾有扩展名,spring 会更改 return 内容类型。
所以在最后看到 .zip 导致 spring 将类型覆盖为 application/zip 。
简介
我有一个关于 RestController 和 Test 的问题。
我有以下 PostMapping
:
@PostMapping(path = "/download/as/zip/{zipFileName}" )
@ResponseBody
public ResponseEntity<InputStreamResource> downloadDocumentZip(@RequestHeader(required=false,name="X-Application") String appName, @RequestBody ZipFileModel zipFileModel, @PathVariable("zipFileName") String zipFileName)
我有以下测试:
Response response = given(this.requestSpecification).port(port)
.filter(document("downloadAsZip",
preprocessRequest(prettyPrint()),
requestHeaders(headerWithName("X-Application").description("Owner application")),
pathParameters(parameterWithName("zipFileName").description("The name of the resulting zip file. Mostly not needed/optional.")))
)
.contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)
.header(new Header(HEADER, "themis"))
.body(jsonContent)
.when()
.post("/download/as/zip/{zipFileName}", "resultFile.zip");
这有效并返回 200。
第一个问题
现在我对测试中.contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)
的含义有点困惑。
Content-type 是返回响应中的 header。但是在这个测试中,它是在提出测试请求时被包含在内的吗? 或者在这种情况下是否表示我们在请求中发送 JSON body?
第二个问题
我知道我的控制器方法应该消耗 JSON 和 returns 字节。 因此,我做出以下更改:
@PostMapping(path = "/download/as/zip/{zipFileName}", 消耗 = MediaType.APPLICATION_JSON_VALUE)
目前有效。
然后我添加以下内容:
@PostMapping(path = "/download/as/zip/{zipFileName}", consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
失败了:
java.lang.AssertionError:
Expected :200
Actual :406
<Click to see difference>
所以我将测试更改为以下内容:
.contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)
.accept(MediaType.APPLICATION_OCTET_STREAM_VALUE)
这又一次失败了。
Expected :200
Actual :406
因此,即使客户端发出与控制器生成的信号相同的接受 header 信号,我们也会出现错误。
问题:
- 那么我们应该还是不应该在请求映射上有
produces=
? - 为什么现在失败了?消费JSON和生产字节有冲突吗?还是测试中的
ContentType
?
问题在于,如果 URL 的结尾有扩展名,spring 会更改 return 内容类型。
所以在最后看到 .zip 导致 spring 将类型覆盖为 application/zip 。