servlet/grails 如何正确地将 mp4 文件提供给 Safari?
How do servlet/grails correctly serve mp4 files to Safari?
在这个简单的代码中:
def index() {
def file = new File('/tmp/big_buck_bunny_720p_50mb.mp4')
println "file = ${file} , length = ${file.length()}"
if (file.exists()) {
webRequest.renderView = false;
response.setContentType("video/mp4")
response.setHeader("Content-disposition", "inline; filename=" + URLEncoder.encode(file.name, "UTF-8"));
response.setHeader("Content-Length", String.valueOf(file.length()));
InputStream is = new FileInputStream(file);
response.outputStream << is
response.outputStream.flush()
response.outputStream.close()
is.close()
}
} // index
它可以正确地将 mp4 文件提供给 Firefox,但在 Safari(OS/X 上的 9.0.1)中,它无法播放,并且服务器报告:
file = /tmp/big_buck_bunny_720p_50mb.mp4 , length = 52464391
| Error 2015-11-23 10:37:13,339 [http-bio-8080-exec-3] ERROR errors.GrailsExceptionResolver - SocketException occurred when processing request: [GET] /hello2/stream/index
Broken pipe. Stacktrace follows:
Message: Broken pipe
Line | Method
->> 109 | socketWrite in java.net.SocketOutputStream
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 153 | write in ''
| 17 | index . . . in hello2.StreamController$$EPUpAtg0
| 198 | doFilter in grails.plugin.cache.web.filter.PageFragmentCachingFilter
| 63 | doFilter . in grails.plugin.cache.web.filter.AbstractFilter
| 1142 | runWorker in java.util.concurrent.ThreadPoolExecutor
| 617 | run . . . . in java.util.concurrent.ThreadPoolExecutor$Worker
^ 745 | run in java.lang.Thread
| Error 2015-11-23 10:37:13,349 [http-bio-8080-exec-3] ERROR errors.GrailsExceptionResolver - IllegalStateException occurred when processing request: [GET] /hello2/stream/index
getOutputStream() has already been called for this response. Stacktrace follows:
Message: Error processing GroovyPageView: getOutputStream() has already been called for this response
Line | Method
->> 648 | doFilter in /hello2/grails-app/views/error.gsp
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Caused by IllegalStateException: getOutputStream() has already been called for this response
->> 100 | flush in java.io.FilterWriter
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 198 | doFilter in grails.plugin.cache.web.filter.PageFragmentCachingFilter
| 63 | doFilter in grails.plugin.cache.web.filter.AbstractFilter
| 1142 | runWorker in java.util.concurrent.ThreadPoolExecutor
| 617 | run . . . in java.util.concurrent.ThreadPoolExecutor$Worker
^ 745 | run in java.lang.Thread
| Error 2015-11-23 10:37:13,354 [http-bio-8080-exec-3] ERROR [/hello2].[grails] - Servlet.service() for servlet grails threw exception
为什么代码在 Firefox 中有效,但在 Safari 中抛出 Broken pipe 或 getOutputStream() has already been called for this response 异常?
如何解决?谢谢。
环境:Grails 2.5.1
=====更新=====
我发现了这个问题:
Mp4 downloading instead of playing in Safari , and there is an URL http://techslides.com/demos/sample-videos/small.mp4
我的Safari可以正常播放视频
我尝试模拟header
$ curl -I http://techslides.com/demos/sample-videos/small.mp4
HTTP/1.1 200 OK
Server: nginx/1.4.1 (Ubuntu)
Date: Mon, 23 Nov 2015 04:25:36 GMT
Content-Type: video/mp4
Content-Length: 383631
Last-Modified: Sun, 16 Feb 2014 18:49:36 GMT
Connection: keep-alive
ETag: "53010840-5da8f"
Accept-Ranges: bytes
除了 ETag ,其他 header 被插入。
但是Safari还是不能播放,服务器报同样的异常。
对于任何对这个问题感兴趣(或陷入困境)的人,我已经找到了解决方案。这不是一个简单的解决方案。
解决方案在此URL:FileServlet supporting resume and caching and GZIP
它适用于 servlet 和 Grails。
在这个简单的代码中:
def index() {
def file = new File('/tmp/big_buck_bunny_720p_50mb.mp4')
println "file = ${file} , length = ${file.length()}"
if (file.exists()) {
webRequest.renderView = false;
response.setContentType("video/mp4")
response.setHeader("Content-disposition", "inline; filename=" + URLEncoder.encode(file.name, "UTF-8"));
response.setHeader("Content-Length", String.valueOf(file.length()));
InputStream is = new FileInputStream(file);
response.outputStream << is
response.outputStream.flush()
response.outputStream.close()
is.close()
}
} // index
它可以正确地将 mp4 文件提供给 Firefox,但在 Safari(OS/X 上的 9.0.1)中,它无法播放,并且服务器报告:
file = /tmp/big_buck_bunny_720p_50mb.mp4 , length = 52464391
| Error 2015-11-23 10:37:13,339 [http-bio-8080-exec-3] ERROR errors.GrailsExceptionResolver - SocketException occurred when processing request: [GET] /hello2/stream/index
Broken pipe. Stacktrace follows:
Message: Broken pipe
Line | Method
->> 109 | socketWrite in java.net.SocketOutputStream
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 153 | write in ''
| 17 | index . . . in hello2.StreamController$$EPUpAtg0
| 198 | doFilter in grails.plugin.cache.web.filter.PageFragmentCachingFilter
| 63 | doFilter . in grails.plugin.cache.web.filter.AbstractFilter
| 1142 | runWorker in java.util.concurrent.ThreadPoolExecutor
| 617 | run . . . . in java.util.concurrent.ThreadPoolExecutor$Worker
^ 745 | run in java.lang.Thread
| Error 2015-11-23 10:37:13,349 [http-bio-8080-exec-3] ERROR errors.GrailsExceptionResolver - IllegalStateException occurred when processing request: [GET] /hello2/stream/index
getOutputStream() has already been called for this response. Stacktrace follows:
Message: Error processing GroovyPageView: getOutputStream() has already been called for this response
Line | Method
->> 648 | doFilter in /hello2/grails-app/views/error.gsp
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Caused by IllegalStateException: getOutputStream() has already been called for this response
->> 100 | flush in java.io.FilterWriter
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 198 | doFilter in grails.plugin.cache.web.filter.PageFragmentCachingFilter
| 63 | doFilter in grails.plugin.cache.web.filter.AbstractFilter
| 1142 | runWorker in java.util.concurrent.ThreadPoolExecutor
| 617 | run . . . in java.util.concurrent.ThreadPoolExecutor$Worker
^ 745 | run in java.lang.Thread
| Error 2015-11-23 10:37:13,354 [http-bio-8080-exec-3] ERROR [/hello2].[grails] - Servlet.service() for servlet grails threw exception
为什么代码在 Firefox 中有效,但在 Safari 中抛出 Broken pipe 或 getOutputStream() has already been called for this response 异常?
如何解决?谢谢。
环境:Grails 2.5.1
=====更新=====
我发现了这个问题:
Mp4 downloading instead of playing in Safari , and there is an URL http://techslides.com/demos/sample-videos/small.mp4
我的Safari可以正常播放视频
我尝试模拟header
$ curl -I http://techslides.com/demos/sample-videos/small.mp4
HTTP/1.1 200 OK
Server: nginx/1.4.1 (Ubuntu)
Date: Mon, 23 Nov 2015 04:25:36 GMT
Content-Type: video/mp4
Content-Length: 383631
Last-Modified: Sun, 16 Feb 2014 18:49:36 GMT
Connection: keep-alive
ETag: "53010840-5da8f"
Accept-Ranges: bytes
除了 ETag ,其他 header 被插入。 但是Safari还是不能播放,服务器报同样的异常。
对于任何对这个问题感兴趣(或陷入困境)的人,我已经找到了解决方案。这不是一个简单的解决方案。
解决方案在此URL:FileServlet supporting resume and caching and GZIP
它适用于 servlet 和 Grails。