【发布时间】:2016-01-17 04:33:15
【问题描述】:
如何在 Phoenix 上实现第一个答案 here 中的流程?起初我以为我必须使用Conn.send_chunked 和Conn.chunk,但我开始意识到我会收到很多请求,而不是发送各种响应。
【问题讨论】:
如何在 Phoenix 上实现第一个答案 here 中的流程?起初我以为我必须使用Conn.send_chunked 和Conn.chunk,但我开始意识到我会收到很多请求,而不是发送各种响应。
【问题讨论】:
如果有人感兴趣,这是我的解决方案。与视频播放器正确对话,也可以处理普通文件。
[range_start, range_end] =
if Enum.empty?(Conn.get_req_header(conn, "range")) do
[0, file.content_length - 1]
else
[rn] = Conn.get_req_header(conn, "range")
res = Regex.run(~r/bytes=([0-9]+)-([0-9])?/, rn)
default_end = Integer.to_string(file.content_length - 1)
{range_start, _} = res |> Enum.at(1) |> Integer.parse
{range_end, _} = res |> Enum.at(2, default_end) |> Integer.parse
[range_start, range_end]
end
content_length = range_end - range_start + 1
conn = conn
|> Conn.put_resp_content_type(file.content_type)
|> Conn.put_resp_header("content-length", Integer.to_string(content_length))
|> Conn.put_resp_header("accept-ranges", "bytes")
|> Conn.put_resp_header("content-disposition", ~s(inline; filename="#{file.filename}"))
|> Conn.put_resp_header("content-range", "bytes #{range_start}-#{range_end}/#{file.content_length}")
|> Conn.send_file(206, "#{files_path}/#{id}", range_start, content_length)
【讨论】:
感谢克里斯蒂安发布您的解决方案!否则我永远不会想到这一点......
对于像我这样遇到此问题并且无法完全使上述 sn-p 工作的任何 Elixir 新手,这是我的完整控制器方法:
def load_song(conn, params) do
filename = List.first(params["song"])
file_path = "priv/static/sounds/#{filename}"
{:ok, stats} = File.stat(file_path)
filesize = stats.size
[range_start, range_end] =
if Enum.empty?(Plug.Conn.get_req_header(conn, "range")) do
[0, filesize - 1]
else
[rn] = Plug.Conn.get_req_header(conn, "range")
res = Regex.run(~r/bytes=([0-9]+)-([0-9])?/, rn)
default_end = Integer.to_string(filesize - 2)
{range_start, _} = res |> Enum.at(1) |> Integer.parse
{range_end, _} = res |> Enum.at(2, default_end) |> Integer.parse
[range_start, range_end]
end
content_length = range_end - range_start + 2
conn
|> Plug.Conn.put_resp_content_type("audio/mpeg")
|> Plug.Conn.put_resp_header("content-length", Integer.to_string(content_length))
|> Plug.Conn.put_resp_header("accept-ranges", "bytes")
|> Plug.Conn.put_resp_header("content-disposition", ~s(inline; filename="#{filename}"))
|> Plug.Conn.put_resp_header("content-range", "bytes #{range_start}-#{range_end}/#{filesize}")
|> Plug.Conn.send_file(206, file_path, range_start, content_length)
end
我已经了解了一些基本的 Elixir 功能,比如别名,可以简化这一点,我猜其他一些编码选择有点不习惯,但上面显示的是一种“插入”方法为您的控制器。
【讨论】:
我为此创建了一个名为 plug_range 的插件,它将捕获每个范围请求并为它们提供服务。 遵循 RFC 仍在进行中,但在此之前它可能会派上用场。
【讨论】: