Skip to content
AITroveRead. Build. Understand.
Make this comfortable

Spring MVC byte ranges: resume an authorized receipt download

Last updated: 5 Oct 20264 min read
tutorial
IntermediateBy AITrove Editorial

Spring MVC can turn a Range request into a partial Resource response when the controller returns a repeatable Resource with a normal 200 response.

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

Java
@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.

spring
spring-web
mvc-range-receipt-download
Storage details