gpt4 book ai didi

http - 在 grails 中通过带有范围 header 的 http 流式传输 mp4 请求

转载 作者:可可西里 更新时间:2023-11-01 16:36:10 30 4
gpt4 key购买 nike

我在使用旧的 grails 2.5.1 应用程序,我注意到服务器提供的 mp4 视频文件无法在 Safari 中播放。我在 SO 上查找了这个问题,并得到一些提示,它与范围 header 有关。但我怀疑我处理范围 header 的方式不太正确。

到目前为止,我发现 Mac OS Safari 11.0 (11604.1.38.1.7)(我现在不关心 ios Safari)发送了两个 GET 请求。首先,它发送一个:

host:     localhost:8080
accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Safari/604.1.38
accept-language: en-us
accept-encoding: gzip, deflate
x-request-time: t=****
x-forwarded-for: *.*.*.*
x-forwarded-host: *.com
x-forwarded-server: *.com
connection: Keep-Alive
cookie: ...TOO BIG TO SHOW HERE
<- "GET /.../videos/lol.mp4 HTTP/1.1" 200 186ms

随后,它发送第二个 GET 请求:

host:     localhost:8080
language: en-us
playback-session-id: 03F1B4E6-F97E-****
bytes=0-1
accept: */*
user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Safari/604.1.38
https://.../videos/lol.mp4
encoding: identity
request-time: t=****
forwarded-for: *.*.*.*
forwarded-host: *.com
forwarded-server: *.com
connection: Keep-Alive
cookie: ...TOO BIG TO SHOW HERE
<- "GET /uiv2/videos/lol.mp4 HTTP/1.1" 206 149ms

调试它很困难,因为 Safari 网络检查器不会向您显示太多信息。事实上,它甚至没有向您显示它发送的所有 header ,所以我不得不从后端获取它。

可以看出,request 1 和 2 的区别在于 2nd 有 playback-session-id 和 range。

困难的部分是找出如何在处理范围和播放 session ID 方面取悦 Safari。

我已经制作了一个 Controller 来返回请求的字节范围,如果它们被请求的话。但仍然没有运气。

import grails.compiler.GrailsTypeChecked
import grails.plugin.springsecurity.annotation.Secured
import asset.pipeline.grails.AssetResourceLocator
import grails.util.BuildSettings
import org.codehaus.groovy.grails.commons.GrailsApplication
import org.springframework.core.io.Resource

class VideoController {
GrailsApplication grailsApplication
AssetResourceLocator assetResourceLocator

public index() {
Resource mp4Resource = assetResourceLocator.findAssetForURI('/../lol.mp4');

response.addHeader("Content-type", "video/mp4")
response.addHeader( 'Accept-Ranges', 'bytes')

String range = request.getHeader('range')
if(range) {
String[] rangeKeyValue = range.split('=')
String[] rangeEnds = rangeKeyValue[1].split('-')
if(rangeEnds.length > 1) {
int startByte = Integer.parseInt(rangeEnds[0])
int endByte = Integer.parseInt(rangeEnds[1])
int contentLength = (endByte - startByte) + 1
byte[] inputBytes = new byte[contentLength]
mp4Resource.inputStream.read(inputBytes, startByte, contentLength)
response.status = 206
response.addHeader( 'Content-Length', "${contentLength}")
response.outputStream << inputBytes

} else {
response.addHeader( 'Content-Length', "${mp4Resource.contentLength()}")
response.outputStream << mp4Resource.inputStream
}
} else {
log.info 'no range, so responding with whole mp4'
response.addHeader( 'Content-Length', "${mp4Resource.contentLength()}")
response.outputStream << mp4Resource.inputStream
}
}
}

在 Safari 控制台中,我得到:

Failed to load resource: Plug-in handled load

没有别的。遗憾的是,网络检查器中的许多字段都是空白的,即使它们显然是在服务器中设置的。

enter image description here

在这一点上我已经尝试了很多东西,任何帮助、指点和技巧都将不胜感激。谢谢你们 :) !

最佳答案

在尝试了很多事情并搜索了很多帖子之后,这个公式奏效了。您需要所有四个 header 。不需要在第一个请求中返回任何东西。这可能不适用于所有浏览器,但适用于 safari。额外的修改可以确保所有浏览器都被处理

class VideoController {
GrailsApplication grailsApplication
AssetResourceLocator assetResourceLocator

public index() {
Resource mp4Resource = assetResourceLocator.findAssetForURI('/../lol.mp4')

String range = request.getHeader('range')
if(range) {
String[] rangeKeyValue = range.split('=')
String[] rangeEnds = rangeKeyValue[1].split('-')
if(rangeEnds.length > 1) {
int startByte = Integer.parseInt(rangeEnds[0])
int endByte = Integer.parseInt(rangeEnds[1])
int contentLength = (endByte - startByte) + 1
byte[] inputBytes = new byte[contentLength]
def inputStream = mp4Resource.inputStream
inputStream.skip(startByte) // input stream always starts at the first byte, so skip bytes until you get to the start of the requested range
inputStream.read(inputBytes, 0, contentLength) // read from the first non-skipped byte
response.reset() // Clears any data that exists in the buffer as well as the status code and headers
response.status = 206
response.addHeader("Content-Type", "video/mp4")
response.addHeader( 'Accept-Ranges', 'bytes')
response.addHeader('Content-Range', "bytes ${startByte}-${endByte}/${mp4Resource.contentLength()}")
response.addHeader( 'Content-Length', "${contentLength}")
response.outputStream << inputBytes
}
}
}
}

关于http - 在 grails 中通过带有范围 header 的 http 流式传输 mp4 请求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46310388/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com