Andy Wilkinson opened SPR-15789 and commented

I've just been pleased to learn that WebFlux automatically supports range requests to a request mapping method that returns a Resource:

@RequestMapping(path = "/")
public Resource test() {
    return new ByteArrayResource(new byte[] {'a', 'b', 'c', 'd', 'e', 'f'});
}
$ curl localhost:8080 -H "Range: bytes=2-4" -i
HTTP/1.1 206 Partial Content
Accept-Ranges: bytes
Content-Type: application/octet-stream
Content-Range: bytes 2-4/6
Content-Length: 3

cde

Unfortunately, if the same controller is implemented using Spring MVC, the full resource content is returned:

$ curl localhost:8080 -H "Range: bytes=2-4" -i
HTTP/1.1 200
Content-Type: application/json
Content-Length: 6
Date: Tue, 18 Jul 2017 13:03:31 GMT

abcdef

It would be beneficial to Boot 2.0's new actuator endpoint infrastructure if Spring MVC offered the same capabilities as WebFlux here.


Affects: 5.0 RC2

Issue Links: - #18407 Add support for http byte-range requests for non-static resources ("is duplicated by")

Referenced from: commits https://github.com/spring-projects/spring-framework/commit/582014e944002609b562f6e4998935c06bbe6922

1 votes, 3 watchers

Comment From: peter-lyons-kehl

Side notes: Are you figuring out how to implement partial downloads (HTTP range)?

In addition to returning Resource, your controller method needs to be annotated with @ResponseBody, too. Otherwise it upsets Spring and it chains the request as if the URL was repeated.

If you do return a Resource, Spring ignores any content type you set by servletResponse.setContentType(String). It probably auto-detects the content type instead.

Alternatively, don't use @ResponseBody and return type org.springframework.http<Resource> and generate it like (in Kotlin):

return ResponseEntity
                .ok()
                .contentLength(resourceLength)
                .contentType(
                        MediaType.parseMediaType("application/octet-stream"))
                .body(fixedLengthInputStream)

If you use InputStreamResource, extend it (for example as an anonymous class) and override its contentLength(), too.