You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用AWS SDK实现视频流:第二次字节范围请求失败

问题分析

错误的核心是:你返回的ByteArrayResource是当前从S3获取的2MB块内容,但Spring的ResourceHttpMessageWriter会读取浏览器发送的Range头(bytes=2097152-),并尝试从这个Resource中从2097152的位置开始读取数据。但你的Resource总长度只有2097152字节(索引范围为0到2097151),2097152的位置超出了资源范围,因此触发了IllegalArgumentException。

解决方案

方案1:返回byte[]而非Resource类型

因为Spring对Resource类型的响应会自动处理请求的Range头,但你已经手动从S3获取了正确的块内容,不需要Spring再做切割。将返回类型改为byte[],让Spring直接输出字节内容即可:

服务层代码修改:

EcsObject ecsObject = awsEcsRepository.getObjectByRange(fileName, bucketName, null, contentRange, correlationId);
byte[] videoBytes = ecsObject.getInputStream().readAllBytes();

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.valueOf("video/webm"));
headers.setContentLength(videoBytes.length); // 设置当前块的实际长度
headers.set(HttpHeaders.CONTENT_RANGE, "bytes " + rangeStart + "-" + rangeEnd + "/" + fileSize);
headers.set(HttpHeaders.ACCEPT_RANGES, "bytes");

return ResponseEntity.status(HttpStatus.PARTIAL_CONTENT)
        .headers(headers)
        .body(videoBytes);

控制器代码修改:

public ResponseEntity<byte[]> getVideoFromS3(@RequestHeader("Range") String range)
{
    return streamingService.getVideoFromS3(range);
}

方案2:调整Range计算并使用InputStreamResource(可选)

如果坚持使用Resource类型,可以改用InputStreamResource,同时修正Range结束值的计算逻辑:2MB块的结束值应为rangeStart + 2097151(因为字节索引从0开始,2MB包含2097152个字节),比如第二次请求的结束值应为2097152 + 2097151 = 4194303(而非你之前写的4194302),避免少返回1字节。

修改后的服务层代码示例:

EcsObject ecsObject = awsEcsRepository.getObjectByRange(fileName, bucketName, null, contentRange, correlationId);
InputStreamResource videoResponse = new InputStreamResource(ecsObject.getInputStream());

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.valueOf("video/webm"));
headers.setContentLength(ecsObject.getContentLength());
headers.set(HttpHeaders.CONTENT_RANGE, "bytes " + rangeStart + "-" + rangeEnd + "/" + fileSize);
headers.set(HttpHeaders.ACCEPT_RANGES, "bytes");

return ResponseEntity.status(HttpStatus.PARTIAL_CONTENT)
        .headers(headers)
        .body(videoResponse);
额外注意事项
  • 当剩余文件长度不足2MB时,rangeEnd应设为总文件大小减1(比如最后一次请求,总文件12MB,最后一个块的rangeStart是10485760,rangeEnd是12582911)。
  • 验证从S3获取的内容长度与你计算的块长度一致,避免出现长度不匹配的问题。

内容的提问来源于stack exchange,提问作者Shannu Bujji

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 04:57:36