【问题标题】:Ranged Response Flow in Phoenix/ElixirPhoenix/Elixir 中的远程响应流
【发布时间】:2016-01-17 04:33:15
【问题描述】:

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

【问题讨论】:

    标签: elixir phoenix-framework


    【解决方案1】:

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

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

    【讨论】:

      【解决方案2】:

      感谢克里斯蒂安发布您的解决方案!否则我永远不会想到这一点......

      对于像我这样遇到此问题并且无法完全使上述 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 功能,比如别名,可以简化这一点,我猜其他一些编码选择有点不习惯,但上面显示的是一种“插入”方法为您的控制器。

      【讨论】:

      • 很高兴它有帮助,我花了整整一个下午才弄清楚,我希望其他人能更快地完成它的答案。我看到你稍微改变了数学。
      • 糟糕,我可能不小心这样做了。我习惯于在比原始字节更高的抽象级别上工作,所以我有点不确定内容长度和文件大小:) 今天下午我必须做一些实验。
      【解决方案3】:

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

      PlugRange

      【讨论】:

        猜你喜欢
        • 2019-01-12
        • 2021-09-08
        • 2015-12-03
        • 2018-05-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-01-04
        • 1970-01-01
        相关资源
        最近更新 更多