Spring MVC can turn a Range request into a partial Resource response when the controller returns a repeatable Resource with a normal 200 response.
Spring MVC byte ranges: resume an authorized receipt download
Return a repeatable resource
A large archived receipt may need resume support after a dropped connection. A controller can return a FileSystemResource through ResponseEntity<Resource>; Spring MVC parses valid byte ranges and writes the selected region. The returned resource must support repeatable reads and a known length. An InputStreamResource is not suitable for this transparent range path. StreamingResponseBody] is a different delivery contract.
Authorize before opening storage
Resolve the receipt through the tenant-scoped storage service, then expose only the authorized file. Do not construct a filesystem path from a client filename or ID. Return status 200 in the controller even when Range is present; the MVC resource writer decides whether the response becomes 206. Apply the appropriate private cache and download-name policy. Private caching] still matters for a partial response.
Exercise real headers
Test a normal GET, Range: bytes=0-46, an invalid range, and a second-tenant request. Check the actual Content-Range, status and selected byte count, rather than only asserting controller return values. Verify that the underlying resource stays readable until the response finishes; deleting a temporary file early can break the transfer.
Implementation contract
@GetMapping(path = "/receipts/{receiptId}/pdf", produces = "application/pdf")
ResponseEntity<Resource> download(
@PathVariable UUID receiptId, Authentication authentication) {
Resource pdf = receiptStorage.authorizedFile(authentication, receiptId);
return ResponseEntity.ok() // MVC changes this to 206 for a valid Range.
.contentType(MediaType.APPLICATION_PDF)
.cacheControl(CacheControl.noStore())
.body(pdf);
}Cost and verification
A range response reads and transfers only the selected bytes, but multiple tiny ranges increase request overhead. Storage still needs an efficient seekable resource and an authorization check on every request.
Common Mistakes
- Do not return InputStreamResource for automatic range handling.
- Do not manually set 206 on the controller ResponseEntity.
- Do not use the request path as a storage path.
Read next
Spring MVC streaming response: stop work when the client disconnects, Spring MVC private Cache-Control: decide who may retain a receipt, Spring MVC Content-Disposition: produce a safe attachment filename, Spring multipart size limits: enforce parser and application budgets, Spring MVC consumes and produces: 415 and 406 are different failures.
