如何使用 Spring MVC 返回视频,以便可以使用 html5 <video> 标签进行导航?
Posted
技术标签:
【中文标题】如何使用 Spring MVC 返回视频,以便可以使用 html5 <video> 标签进行导航?【英文标题】:How do I return a video with Spring MVC so that it can be navigated using the html5 <video> tag? 【发布时间】:2014-01-05 05:48:03 【问题描述】:如果我在 Web 服务器 (Tomcat) 中有一个文件并创建了一个标签,我可以观看视频、暂停、浏览它,并在完成后重新启动它。
但如果我创建一个 REST 接口,在请求时发送视频文件,并将其 URL 添加到标签,我只能播放和暂停。 无后退、无快进、无导航,什么都没有。
那么,有没有办法解决这个问题?我在某处遗漏了什么吗?
视频文件与 REST 接口在同一台服务器上,REST 接口只检查会话,并在找出应该发送哪个视频后发送视频。
这些是我迄今为止尝试过的方法。它们都可以工作,但没有一个允许导航。
方法一,响应实体:
/*
* This will actually load the whole video file in a byte array in memory,
* so it's not recommended.
*/
@RequestMapping(value = "/id/preview", method = RequestMethod.GET)
@ResponseBody public ResponseEntity<byte[]> getPreview1(@PathVariable("id") String id, HttpServletResponse response)
ResponseEntity<byte[]> result = null;
try
String path = repositoryService.findVideoLocationById(id);
Path path = Paths.get(pathString);
byte[] image = Files.readAllBytes(path);
response.setStatus(HttpStatus.OK.value());
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
headers.setContentLength(image.length);
result = new ResponseEntity<byte[]>(image, headers, HttpStatus.OK);
catch (java.nio.file.NoSuchFileException e)
response.setStatus(HttpStatus.NOT_FOUND.value());
catch (Exception e)
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
return result;
方法二,流复制:
/*
* IOUtils is available in Apache commons io
*/
@RequestMapping(value = "/id/preview2", method = RequestMethod.GET)
@ResponseBody public void getPreview2(@PathVariable("id") String id, HttpServletResponse response)
try
String path = repositoryService.findVideoLocationById(id);
File file = new File(path)
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
response.setHeader("Content-Disposition", "attachment; filename="+file.getName().replace(" ", "_"));
InputStream iStream = new FileInputStream(file);
IOUtils.copy(iStream, response.getOutputStream());
response.flushBuffer();
catch (java.nio.file.NoSuchFileException e)
response.setStatus(HttpStatus.NOT_FOUND.value());
catch (Exception e)
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
方法三,文件系统资源:
@RequestMapping(value = "/id/preview3", method = RequestMethod.GET)
@ResponseBody public FileSystemResource getPreview3(@PathVariable("id") String id, HttpServletResponse response)
String path = repositoryService.findVideoLocationById(id);
return new FileSystemResource(path);
【问题讨论】:
我相信如果视频正在流式传输,则无法导航,而不是完全可用的文件。但我不确定。 我喜欢第三种方法。方法 1 很昂贵,并且方法 1 和 2 都违反了 MVC 模式(通过使用HttpServletResponse
的 OutputStream
)。控制器应将视图任务委托给View
或HttpMessageConverter
。
不幸的是,两者都不足以用于视频流,因为必须处理部分 http 请求。我添加了一个控制器类,它管理这些类型的请求,完全独立于任何服务。
【参考方案1】:
要支持 Safari,您必须处理范围请求并提供正确的 206 返回码。 https://www.rfc-editor.org/rfc/rfc7233
https://melgenek.github.io/spring-video-service 是一个 Spring 示例。
【讨论】:
同意。处理部分请求是执行此操作的唯一方法,它适用于所有浏览器。【参考方案2】:处理非静态资源的简单解决方案:
@SpringBootApplication
public class DemoApplication
private final static File MP4_FILE = new File("/home/ego/bbb_sunflower_1080p_60fps_normal.mp4");
public static void main(String[] args)
SpringApplication.run(DemoApplication.class, args);
@Controller
final static class MyController
@Autowired
private MyResourceHttpRequestHandler handler;
// supports byte-range requests
@GetMapping("/")
public void home(
HttpServletRequest request,
HttpServletResponse response
) throws ServletException, IOException
request.setAttribute(MyResourceHttpRequestHandler.ATTR_FILE, MP4_FILE);
handler.handleRequest(request, response);
// does not support byte-range requests
@GetMapping(path = "/plain", produces = "video/mp4")
public FileSystemResource plain()
return new FileSystemResource(MP4_FILE);
@Component
final static class MyResourceHttpRequestHandler extends ResourceHttpRequestHandler
private final static String ATTR_FILE = MyResourceHttpRequestHandler.class.getName() + ".file";
@Override
protected Resource getResource(HttpServletRequest request) throws IOException
final File file = (File) request.getAttribute(ATTR_FILE);
return new FileSystemResource(file);
(受 Spring Boots LogFileMvcEndpoint 启发,或多或少等于我后来发现的 Paul-Warrens (@paul-warren) StoreByteRangeHttpRequestHandler)。
希望这是 Spring 将在不久的将来支持的东西,请参阅 https://jira.spring.io/browse/SPR-13834(请投票)。
【讨论】:
ERROR 12362 --- [nio-8080-exec-2] oaccC[.[.[/].[dispatcherServlet] :Servlet.service() 用于 servlet [dispatcherServlet] 在上下文中的路径 [ ] 抛出异常 [Circular view path [plain]: 将再次分派回当前处理程序 URL [/plain]。检查您的 ViewResolver 设置! (提示:由于默认视图名称生成,这可能是未指定视图的结果。)] 根本原因 在 oops 建议中添加 @ResponseBody 即可解决问题 既然 Spring 支持该功能,您能否更新您的答案? @BrianClozel 你能告诉我这在哪里支持吗?任何链接,在 Spring 中,我尝试查看 Spring 参考文档和上述 jira,但找不到任何链接。【参考方案3】:我知道这是一篇旧帖子,但如果它对其他提出相同/类似问题的人有用。
现在有像Spring Content 这样的项目本身就支持视频流。最简单的实现所需的所有代码是:-
@StoreRestResource(path="videos")
public interface VideoStore extends Store<String>
这足以创建一个 Java API 和一组允许您 PUT/POST、GET 和 DELETE 视频流的 REST 端点。 GET 支持字节范围,可以在 html5 视频播放器等中正常播放。
【讨论】:
听起来不错。我会仔细看看的。谢谢【参考方案4】:HTTP 恢复下载功能可能是您的朋友。我以前也有同样的问题。实现 http 范围后,视频中的导航是可能的:
http://balusc.blogspot.com/2009/02/fileservlet-supporting-resume-and.html
【讨论】:
这正是问题所在!在修改该页面中的脚本以满足我的需要(Spring-MVC 等)之后,它运行良好。我可以从日志中看到 Chrome 确实在进行多次调用,发出部分请求并尊重缓存配置。非常感谢,你拯救了我的一天:-)【参考方案5】:其实是前端显示
每个浏览器针对一种特殊的视频格式,都有一个默认的控制面板。
您可以使用 html 和 css 通过媒体 API 创建自己的控件。 Media api
来自Div into HTML5 [默认情况下,
【讨论】:
我知道,但我认为这个控件的行为会根据文件的接收方式而有所不同。 我不这么认为。它只是 video 标签 src 属性的 url。浏览器只知道从 url 加载字节以及视频是否已完全下载。它不知道服务器是否将所有字节都放入响应中。 事实证明 Chrome 做得更多。它会尝试部分下载视频,尽管在指向文件时默认启用该功能,但我必须手动对其进行编码,就像 @user3395533 所说的以上是关于如何使用 Spring MVC 返回视频,以便可以使用 html5 <video> 标签进行导航?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Spring MVC 中返回 403 Forbidden?
如何正确实现使用 Spring MVC\Boot 返回图像列表的 REST 服务?
如何使用 Spring Security / Spring MVC 处理表单登录