Phoenix / Elixir的远程响应流程

时间:2015-10-18 22:43:42

标签: elixir phoenix-framework

如何在Phoenix的第一个答案here中实现流程?起初我以为我必须使用\nConn.send_chunked,但我开始意识到我会收到很多请求,而不是发送各种回复。

3 个答案:

答案 0 :(得分:2)

如果有人感兴趣,这是我的解决方案。与视频播放器正确对话,并处理普通文件。

[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)

答案 1 :(得分:1)

感谢发布您的解决方案Cristian!我从来没有想过这个......否则......

对于任何像我这样的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功能,比如混叠,这会简化这一点,而且我猜测其他一些编码选择有点不合时宜,但上面的展示工作如下a"跌入"控制器的方法。

答案 2 :(得分:1)

我为这个名为plug_range创建了一个插件,它将捕获每个范围请求并提供它们。 遵循RFC仍然是一项正在进行中的工作,但在此之前它可能会派上用场。

PlugRange