我有以下问题。声音从公共文件夹中隐藏,因为只有某些用户应该有权访问声音文件。所以我做了一个方法,它的作用就像一个声音的url,但首先计算当前用户是否被允许访问这个文件。
该文件由 send_data 方法发送。问题只是,即使它可以正常工作,我的工作也会很慢......我用来播放声音的 jplayer 插件的开发人员告诉我,我应该能够接受字节范围请求以使其正常工作...
如何通过发送带有 send_data 或 send_file 的文件在 Rails 控制器中执行此操作?
谢谢,马库斯
我有以下问题。声音从公共文件夹中隐藏,因为只有某些用户应该有权访问声音文件。所以我做了一个方法,它的作用就像一个声音的url,但首先计算当前用户是否被允许访问这个文件。
该文件由 send_data 方法发送。问题只是,即使它可以正常工作,我的工作也会很慢......我用来播放声音的 jplayer 插件的开发人员告诉我,我应该能够接受字节范围请求以使其正常工作...
如何通过发送带有 send_data 或 send_file 的文件在 Rails 控制器中执行此操作?
谢谢,马库斯
我已经能够使用 send_file 成功地提供文件。虽然我遇到了一个问题,但寻找歌曲的较早部分会导致一个新的请求,这使得歌曲从 0:00 重新开始,而不是从搜索栏的真实位置重新开始。到目前为止,这是我为我工作的:
file_begin = 0
file_size = @media.file_file_size
file_end = file_size - 1
if !request.headers["Range"]
status_code = "200 OK"
else
status_code = "206 Partial Content"
match = request.headers['range'].match(/bytes=(\d+)-(\d*)/)
if match
file_begin = match[1]
file_end = match[1] if match[2] && !match[2].empty?
end
response.header["Content-Range"] = "bytes " + file_begin.to_s + "-" + file_end.to_s + "/" + file_size.to_s
end
response.header["Content-Length"] = (file_end.to_i - file_begin.to_i + 1).to_s
response.header["Last-Modified"] = @media.file_updated_at.to_s
response.header["Cache-Control"] = "public, must-revalidate, max-age=0"
response.header["Pragma"] = "no-cache"
response.header["Accept-Ranges"]= "bytes"
response.header["Content-Transfer-Encoding"] = "binary"
send_file(DataAccess.getUserMusicDirectory(current_user.public_token) + @media.sub_path,
:filename => @media.file_file_name,
:type => @media.file_content_type,
:disposition => "inline",
:status => status_code,
:stream => 'true',
:buffer_size => 4096)
这是我的版本。我使用 gem 'ogginfo-rb' 来计算正确提供 ogg 文件所需的持续时间。ps 我总是有三种格式——wav、mp3、ogg。
the_file = File.open(file_path)
file_begin = 0
file_size = the_file.size
file_end = file_size - 1
if request.headers['Range']
status_code = :partial_content
match = request.headers['range'].match(/bytes=(\d+)-(\d*)/)
if match
file_begin = match[1]
file_end = match[1] if match[2] and not match[2].empty?
end
response.headers['Content-Range'] = "bytes #{file_begin}-#{file_end.to_i + (match[2] == '1' ? 1 : 0)}/#{file_size}"
else
status_code = :ok
end
response.headers['Content-Length'] = (file_end.to_i - file_begin.to_i + 1).to_s
response.headers['Last-Modified'] = the_file.mtime
response.headers['Cache-Control'] = 'public, must-revalidate, max-age=0'
response.headers['Pragma'] = 'no-cache'
response.headers['Accept-Ranges'] = 'bytes'
response.headers['Content-Transfer-Encoding'] = 'binary'
require 'ogginfo-rb'
ogginfo = Ogg::Info::open(the_file.path.gsub(/.mp3|.wav/,'.ogg'))
duration = ogginfo.duration.to_f
response.headers['Content-Duration'] = duration
response.headers['X-Content-Duration'] = duration
send_file file_path,
filename: "#{call.id}.#{ext}",
type: Mime::Type.lookup_by_extension(ext),
status: status_code,
disposition: 'inline',
stream: 'true',
buffer_size: 32768
我使用了 Garrett 的答案并对其进行了修改(包括一两个错误修复)。我还使用send_data
而不是从文件中读取:
def stream_data data, options={}
range_start = 0
file_size = data.length
range_end = file_size - 1
status_code = "200"
if request.headers["Range"]
status_code = "206"
request.headers['range'].match(/bytes=(\d+)-(\d*)/).try do |match|
range_start = match[1].to_i
range_end = match[2].to_i unless match[2]&.empty?
end
response.header["Content-Range"] = "bytes #{range_start}-#{range_end}/#{file_size}"
end
response.header["Content-Length"] = (range_end - range_start + 1).to_s
response.header["Accept-Ranges"] = "bytes"
send_data(data[range_start, range_end],
filename: options[:filename],
type: options[:type],
disposition: "inline",
status: status_code)
end
另一个修改版本 - 我试图下载一个 zip 文件作为二进制内容,这对我有用 -
def byte_range_response (request, response, content)
file_begin = 0
file_size = content.bytesize
file_end = file_size - 1
status_code = '206 Partial Content'
match = request.headers['range'].match(/bytes=(\d+)-(\d*)/)
if match
file_begin = match[1]
file_end = match[2] if match[2] && !match[2].empty?
end
content_length = file_end.to_i - file_begin.to_i + 1
response.header['Content-Range'] = 'bytes ' + file_begin.to_s + '-' + file_end.to_s + '/' + file_size.to_s
response.header['Content-Length'] = content_length.to_s
response.header['Cache-Control'] = 'public, must-revalidate, max-age=0'
response.header['Pragma'] = 'no-cache'
response.header['Accept-Ranges']= 'bytes'
response.header['Content-Transfer-Encoding'] = 'binary'
send_data get_partial_content(content, content_length, file_begin.to_i), type: 'application/octet-stream', status: status_code
end
def get_partial_content(content, content_length, offset)
test_file = Tempfile.new(['test-file', '.zip'])
test_file.puts(content)
partial_content = IO.binread(test_file.path, content_length, offset)
test_file.close
test_file.unlink
partial_content
end