使用Spring WebFlux开发视频流简单案例与源码 | Vinsguru


展示我们如何使用Spring WebFlux实现视频流。这将比您想象的要简单得多,因为 Spring 为我们完成了所有繁重的工作。这是一个简单有趣的项目,用于演示 Spring WebFlux 的工作原理。
 
需求用例
您通过Netflix观看电影 或通过YouTube 观看视频教程时,浏览器客户端不会下载整个视频内容。它首先获取一些内容。在播放内容时,它还会以流式传输方式获取接下来的几个块。这样我们就可以让用户在点击某个视频时立即与视频互动,而不是让用户等待下载整个内容。
很多时候,用户也会通过点击/拖动搜索栏来尝试在中间的某个地方观看视频,如上图所示。在这种情况下,不需要从一开始就获取视频块。相反,客户端将请求服务器从特定字节索引提供视频内容。服务器将接受字节范围请求并相应地提供内容。
我们将开发一个简单的应用程序来提供视频内容。我们将有一个 HTML UI。当用户点击播放按钮时,服务器会收到请求并播放内容。
用户可以随时调整搜索栏以观看视频。
 
开发过程
当我们点击播放按钮时,它会向服务器发送一个请求到一个端点(http://localhost:8080/video/tom-jerry)

<video src="video/tom-jerry" width="720px" height="480px" controls preload="none">

</video>

服务类非常简单。只需获取Resource对象并返回即可。

@Service
public class StreamingService {

    private static final String FORMAT = "classpath:videos/%s.mp4";

    @Autowired
    private ResourceLoader resourceLoader;

    public Mono<Resource> getVideo(String title) {
        return Mono.fromSupplier(() -> this.resourceLoader.getResource(String.format(FORMAT, title)));
    }

}

下面是控制器——我们在这里获取视频标题名称并加载相应的视频资源。
  • Range 请求标头包含客户端可能发送的字节范围请求。
  • 我没有使用 Range 请求标头,只是在控制台上打印它。但是 Spring 为我们使用了它。我们可以在演示中看到。
  • 不要忘记添加内容类型“ video/mp4 ”。

@RestController
public class StreamingController {

    @Autowired
    private StreamingService service;

    @GetMapping(value = "video/{title}", produces = "video/mp4")
    public Mono<Resource> getVideo(@PathVariable String title, @RequestHeader(
"Range") String range) {
        System.out.println(range);
        return service.getVideo(title);
    }

}

就是这样。这很简单。运行应用程序。

curl http://localhost:8080/video/tom-jerry -i -H "Range: bytes=0-500"

  • 我们可以在服务器端看到如下所示的输出。
    • 它表明它已收到请求头中的字节范围。

2021-08-22 16:02:08.845  INFO 25964 --- [           main] o.s.b.web.embedded.netty.NettyWebServer  : Netty started on port 8080
2021-08-22 16:02:08.864  INFO 25964 --- [           main] c.v.w.WebfluxVideoStreamingApplication   : Started WebfluxVideoStreamingApplication in 2.006 seconds (JVM running for 2.455)
bytes=0-500

  • curl 客户端响应可能是这样的。
    • 注意HTTP – 206状态代码,因为它是部分内容。
    • 视频总长度为21589849字节。
    • 我们收到了0-500个字节,即501 个字节。
    • 在标头之后,以字节为单位的响应不是可读格式。让我们不用担心。

HTTP/1.1 206 Partial Content
Accept-Ranges: bytes
Content-Type: video/mp4
Content-Range: bytes 0-500/21589849
Content-Length: 501

 ftypisomisomiso2avc1mp4free...


  • 我们可以调整字节范围并相应地接收视频响应。
  • 现在让我们访问 HTML 页面并单击播放按钮。
    • 我们可以看到许多请求(按顺序)到服务器以获取视频内容。
    • 检查状态代码为 206 的服务器响应,说它是部分内容。
    • 您可以调整搜索栏,我们将看到为部分字节内容发送了一个新请求。

 
Spring WebFlux 还支持功能端点。除了 RestController,我们还可以使用功能端点提供内容,如下所示。
@Configuration
public class FunctionalEndPointConfig {

    @Autowired
    private StreamingService service;

    @Bean
    public RouterFunction<ServerResponse> router(){
        return RouterFunctions.route()
                .GET("fun-ep/video/{title}", this::videoHandler)
                .build();
    }

    private Mono<ServerResponse> videoHandler(ServerRequest serverRequest){
        String title = serverRequest.pathVariable(
"title");
        return ServerResponse.ok()
                .contentType(MediaType.valueOf(
"video/mp4"))
                .body(this.service.getVideo(title), Resource.class);
    }

}

  • 在这种情况下,视频标签 src 应如下所示。

<video src="fun-ep/video/tom-jerry" width="720px" height="480px" controls preload="none">

</video>

 
我们能够使用 Spring WebFlux成功演示视频流。我们还了解到,我们没有做任何特殊的事情来处理 HTTP Range 请求,因为 Spring 会处理它。
源代码可在此处获得