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

长视频响应过慢:如何优化HTTP GET返回视频的业务逻辑?

问题根源分析

你现在的问题核心在于一次性把整个长视频加载到内存中——IOUtils.toByteArray(url)会把远程视频的全部内容读取到字节数组里,只有当整个视频下载完成后,才会开始向客户端返回响应。这不仅会占用大量服务器内存,还会让客户端等待极长的时间才能收到第一个字节。

解决方案:流式分块传输

我们需要改成边下载边输出的流式逻辑,让服务器不用缓存整个视频,同时客户端能立刻开始接收数据。下面是具体的改写方案:

1. 重写videoAsStream方法,实现流式传输

把一次性读取全部内容改成逐块读取远程流,并直接写入响应输出流,用try-with-resources确保输入流自动关闭,避免资源泄漏:

@Override
public StreamingOutput videoAsStream(final String videoUrl) {
    try {
        final URL url = new URL(videoUrl);
        return output -> {
            // 使用try-with-resources自动关闭输入流
            try (InputStream inputStream = url.openStream()) {
                // 逐块复制流,默认缓冲区大小足够处理大多数场景
                IOUtils.copy(inputStream, output);
                output.flush();
            }
        };
    } catch (final MalformedURLException e) {
        log.error("Url exception for url {}", videoUrl);
        throw new UncheckedIOException(e);
    }
}

2. 增强REST响应的分块传输支持

在返回Response时,明确启用HTTP分块传输编码,让客户端知道可以逐步接收数据:

@GET 
@Path("/test") 
public Response test(@QueryParam("url") final String videoUrl) {
    final CrawlerResult result = this.crawlerService.crawl(videoUrl);
    if (result.isSuccess()) {
        final StreamingOutput fileStream = this.crawlerService.videoAsStream(result.getResult());
        return Response.ok(fileStream, "video/mp4") // 更准确的媒体类型,比APPLICATION_OCTET_STREAM更友好
                .header("content-disposition", "attachment; filename=\"movie.mp4\"") // 修正引号格式,避免潜在解析问题
                .header("Transfer-Encoding", "chunked")
                .build();
    } else {
        return Response.status(Response.Status.NOT_ACCEPTABLE)
                .entity(result)
                .build();
    }
}

额外优化建议

  • 动态生成文件名:可以从原视频URL中提取真实文件名,替换固定的movie.mp4,比如通过new URL(videoUrl).getPath().substring(new URL(videoUrl).getPath().lastIndexOf('/') + 1)来获取原文件名,提升用户体验。
  • 添加超时控制:远程视频下载可能卡住,建议给URL连接设置超时时间,避免线程长时间阻塞:
final URL url = new URL(videoUrl);
URLConnection connection = url.openConnection();
connection.setConnectTimeout(5000); // 连接超时5秒
connection.setReadTimeout(10000); // 读取超时10秒
InputStream inputStream = connection.getInputStream();

这样修改后,服务器会在读取到远程视频的第一块数据时就开始向客户端返回,用户不用等整个视频下载完成,同时服务器内存占用也会大幅降低,长视频的响应体验会立刻改善。

内容的提问来源于stack exchange,提问作者Almas Abdrazak

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:45:54