背景
最近在做一个项目,要用到网页视频播放技术,调研了下现在主流的视频播放技术主要有两种,一是基于Adobe Flash,二是基于HTML5中video标签。两种方式各有利弊。
Adobe Flash的方式需要安装插件,并且不支持Safari浏览器。
HTML5 video标签仅支持可以渲染HTML5的浏览器,IE的早期系列都不支持。并且考虑到各种浏览器兼容,仅支持H.264编码的MP4格式。
最后的决定是抛弃早起IE的版本,使用HTML5的video标签,好处是开发方便,并且富文本编辑框架用的是CKEditor,集成了HTML5 video标签。
使用
<head>
<link href= "http://vjs.zencdn.net/5.8.8/video-js.css" rel= "stylesheet" >
<!-- If you'd like to support IE8 -->
<script src= "http://vjs.zencdn.net/ie8/1.1.2/videojs-ie8.min.js" ></script>
</head>
<body>
<video id= "my-video" class= "video-js" controls preload= "auto" width= "640" height= "264"
poster= "MY_VIDEO_POSTER.jpg" data-setup= "{}" >
<source src= "MY_VIDEO.mp4" type= 'video/mp4' >
<source src= "MY_VIDEO.webm" type= 'video/webm' >
<p class= "vjs-no-js" >
To view this video please enable JavaScript, and consider upgrading to a web browser that
<a href= "http://videojs.com/html5-video-support/" target= "_blank" > supports HTML5 video</a>
</p>
</video>
<script src= "http://vjs.zencdn.net/5.8.8/video.js" ></script>
</body>
问题
其中遇到一个问题就是在Iphone的Safari浏览器下视频不播放的问题,在使用了videojs之后报错如下:The media could not be loaded, either because the server or network failed or because the format is not supported.
VideoJs官网有一个BUG说Demo中单引号的问题https://github.com/videojs/video.js/issues/2945#event-500299257 ,修改后依然不好用。而当我引入其他网站的视频源的时候是好用的可以正常播放,<source src="http://diveintohtml5.info/i/pr6.mp4" type="video/mp4">
,所以怀疑是本地Tomcat服务器返回静态资源的Http Response Header有问题。
[ root@localhost backup]# curl -v http://diveintohtml5.info/i/pr6.mp4 > remote
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 -- :--:-- 0:00:03 -- :--:-- 0* About to connect() to diveintohtml5.info port 80 ( #0)
* Trying 64.111.107.187...
0 0 0 0 0 0 0 0 -- :--:-- 0:00:05 -- :--:-- 0* Connected to diveintohtml5.info ( 64.111.107.187) port 80 ( #0)
> GET /i/pr6.mp4 HTTP/1.1
> User-Agent: curl/7.29.0
> Host: diveintohtml5.info
> Accept: * /*
>
< HTTP/1.1 200 OK
< Date: Tue, 28 Jun 2016 03:32:32 GMT
< Server: Apache
< Last-Modified: Mon, 26 Mar 2012 22:30:07 GMT
< ETag: "f94bf1-4bc2cea9419c0"
< Accept-Ranges: bytes
< Content-Length: 16337905
< Cache-Control: max-age= 31536000
< Expires: Wed, 28 Jun 2017 03:32:32 GMT
< Content-Type: video/mp4
<
{ [ data not shown]
100 15.5M 100 15.5M 0 0 692k 0 0:00:23 0:00:23 -- :--:-- 1303k
* Connection #0 to host diveintohtml5.info left intact
[ root@localhost backup]# curl -v http://localhost/TestSpring/resources/mp4/pr6.mp4 > local
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 -- :--:-- -- :--:-- -- :--:-- 0* About to connect() to localhost port 80 ( #0)
* Trying localhost...
* Connected to localhost ( 127.0.0.1) port 80 ( #0)
> GET /TestSpring/resources/mp4/pr6.mp4 HTTP/1.1
> User-Agent: curl/7.29.0
> Host: localhost
> Accept: * /*
>
< HTTP/1.1 200 OK
< Server: Apache-Coyote/1.1
< Last-Modified: Tue, 28 Jun 2016 01:36:45 GMT
< Content-Type: video/mp4; charset = UTF-8
< Content-Length: 16337905
< Date: Tue, 28 Jun 2016 03:34:24 GMT
<
{ [ data not shown]
100 15.5M 100 15.5M 0 0 79.1M 0 -- :--:-- -- :--:-- -- :--:-- 79.9M
* Connection #0 to host localhost left intact
经过对比发现本地Tomcat部署的服务器在请求MP4静态资源的时候,Response Header中缺少一项Accept-Ranges: bytes
,经过查询 发现此标识表示该资源支持byte形式资源范围请求。
解决方案
继续查询Tomcat方向修改HTTP Response无果。于是回归到项目级别想办法,可以用Filter来解决。定义一个Filter拦截器,对以.MP4结尾的请求URI统一在HTTPResponse中添加Accept-Ranges
web.xml
<filter>
<filter-name> mp4Filter</filter-name>
<filter-class> com.freud.framework.adapter.filter.MP4Filter</filter-class>
<init-param>
<param-name> AcceptRange</param-name>
<param-value> bytes</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name> mp4Filter</filter-name>
<url-pattern> *.mp4</url-pattern>
</filter-mapping>
MP4Filter.java
package com.freud.framework.adapter.filter ;
import java.io.IOException ;
import javax.servlet.Filter ;
import javax.servlet.FilterChain ;
import javax.servlet.FilterConfig ;
import javax.servlet.ServletException ;
import javax.servlet.ServletRequest ;
import javax.servlet.ServletResponse ;
import javax.servlet.http.HttpServletResponse ;
public class MP4Filter implements Filter {
private String acceptRange = "none" ;
private static final String ACCEPT_RANGE = "AcceptRange" ;
@Override
public void destroy () {
}
@Override
public void doFilter ( ServletRequest req , ServletResponse res ,
FilterChain chain ) throws IOException , ServletException {
(( HttpServletResponse ) res ). setHeader ( "Accept-Ranges" , acceptRange );
chain . doFilter ( req , res );
}
@Override
public void init ( FilterConfig config ) throws ServletException {
String temp = config . getInitParameter ( ACCEPT_RANGE );
if ( temp != null )
acceptRange = temp ;
}
}
结果发现依旧不行,不过这个故事告诉我,买了一年的《HTTP协议详解》不能再蹭灰了,要好好看看啊,少年!要不就不至于这么被动了。
继续往下走,想起来在项目中使用的Spring MVC,而DispatcherServlet我配置的是<url-pattern>/</url-pattern>
,所有静态文件都是走的Spring MVC的<mvc:resources mapping="/resources/**" location="/resources/" />
,会不会是这个原因呢,于是自己重新写个最简单的Web项目。部署上去一看,我去,还真是。赶紧想办法。
解决方案就是在web.xml文件中添加如下配置,并且要写在DispatcherServlet的前面, 让defaultServlet先拦截,这个就不会进入Spring了。
<servlet-mapping>
<servlet-name> default</servlet-name>
<url-pattern> *.mp4</url-pattern>
</servlet-mapping>
附:
Tomcat, Jetty, JBoss, and GlassFish
默认 Servlet的名字 – “default”
Google App Engine
默认 Servlet的名字 – “_ah_default”
Resin
默认 Servlet的名字 – “resin-file”
WebLogic
默认 Servlet的名字 – “FileServlet”
WebSphere
默认 Servlet的名字 – “SimpleFileServlet”
至此,折腾了我几个星期的难题终于解决了。大功告成!总结下来算是第一次用HTML5的新特性,不熟悉,并且对Spring MVC的底层也没有那么深入,还有HTTP协议。最近几个月,有的书看了。恶补。
参考资料
《dive into html5》: http://diveintohtml5.info/video.html
google 搜索镜像 :https://muzhiso.wallpai.com/#q=html5+video+iphone+not+working
videojs官网 :http://www.videojs.com/
videojs的BUG :https://github.com/videojs/video.js/issues/2945#event-500299257
HTTP头域列表与解释 之 response篇 : http://www.cnblogs.com/lwhkdash/archive/2012/10/16/2726823.html
How to modify default tomcat http header property “Server: Apache-Coyote/1.1” : http://grokbase.com/t/tomcat/users/082pbj1cb8/how-to-modify-default-tomcat-http-header-property-server-apache-coyote-1-1
SpringMVC访问静态资源的三种方式 http://blog.163.com/koko_qiang/blog/static/207213184201382091154584/