Rails:从另一台服务器下载文件(无需读取文件)

时间:2022-01-04 11:32:44

I have a rails application that has links to download a files from another server. I want to try and prevent the actual file url/locations from being "easily" detectable.

我有一个rails应用程序,它有链接从另一台服务器下载文件。我想尝试防止实际的文件URL /位置被“轻易”检测到。

I tried using send_file but this only appears to work with local files?

我尝试使用send_file,但这似乎只适用于本地文件?

I then tried with send_data - this only seems to work when first reading the file (e.g. file.open ...). I want to be able to send the file without reading it as some of the files are very large and therefore takes ages and has no user feedback etc...

然后我尝试使用send_data - 这似乎只在第一次读取文件时起作用(例如file.open ...)。我希望能够在不读取文件的情况下发送文件,因为有些文件非常大,因此需要很长时间而且没有用户反馈等...

Basically, I want the same behavior as if I was to simply link to/provide the direct file url: that the download opens and starts from the browser.

基本上,我想要相同的行为,就像我只是链接到/提供直接文件URL:下载打开并从浏览器启动。

As I mentioned The reason I want to handle my downloads via a controller (using send_file/data methods) is that I do want the location of the files to be "easily" detectable.

正如我所提到的,我想通过控制器(使用send_file / data方法)处理我的下载的原因是我确实希望“轻松”检测文件的位置。

I hope I have explained this well enough :)

我希望我已经解释得这么好:)

Thanks for any advice

谢谢你的建议

Cheers, Jon.

干杯,乔恩。

1 个解决方案

#1


1  

So you want to stream the data from a public URL to a client without reading it? You're going to have to read it somehow if you want to send it to a client. A redirect is the best solution here, but you don't like redirects because the public URL is ugly.

那么您想要将数据从公共URL流式传输到客户端而无需读取它吗?如果你想将它发送给客户端,你将不得不以某种方式阅读它。重定向是最好的解决方案,但您不喜欢重定向,因为公共URL很难看。

You could try streaming the response_body (which accepts enumerbles) from a Net::HTTP read_body (which produces an enumerable). That might keep your memory footprint down.

您可以尝试从Net :: HTTP read_body(生成可枚举的)流式传输response_body(它接受enumerbles)。这可能会降低你的记忆力。

def DownloadController
  def show
    source = URI('http://www.example.com/some-big-pdf.pdf')

    # Tell the client to download the response with given filename
    headers['Content-Disposition'] = 'attachment; filename="some-big-pdf.pdf"'

    Net::HTTP.start(source.host, source.port) do |http|
      req = Net::HTTP::Get.new source

      http.request(req) do |res|
        self.response_body = res.read_body
      end
    end
  end
end

Edit: Of course send_data can also read from buffers:

编辑:当然send_data也可以从缓冲区中读取:

http.request(req) do |res|
  send_data res.read_body, filename: 'some-big-pdf.pdf', disposition: 'download'
end

However, be aware that this will tie up a worker process until complete. You should ensure that you have enough workers to handle simultaneous downloads. You may also want to look into doing this upstream within your webserver (NGINX?) rather than inside Rails.

但是,请注意,这将占用工作进程直到完成。您应该确保有足够的工作人员来处理同时下载。您可能还想在Web服务器(NGINX?)而不是Rails内部进行上游调查。

See Net::HTTP#read_body and ActionController::Metal#response_body= for more details on these methods. See also https://coderwall.com/p/kad56a/streaming-large-data-responses-with-rails

有关这些方法的更多详细信息,请参阅Net :: HTTP #read_body和ActionController :: Metal#response_body =。另见https://coderwall.com/p/kad56a/streaming-large-data-responses-with-rails

#1


1  

So you want to stream the data from a public URL to a client without reading it? You're going to have to read it somehow if you want to send it to a client. A redirect is the best solution here, but you don't like redirects because the public URL is ugly.

那么您想要将数据从公共URL流式传输到客户端而无需读取它吗?如果你想将它发送给客户端,你将不得不以某种方式阅读它。重定向是最好的解决方案,但您不喜欢重定向,因为公共URL很难看。

You could try streaming the response_body (which accepts enumerbles) from a Net::HTTP read_body (which produces an enumerable). That might keep your memory footprint down.

您可以尝试从Net :: HTTP read_body(生成可枚举的)流式传输response_body(它接受enumerbles)。这可能会降低你的记忆力。

def DownloadController
  def show
    source = URI('http://www.example.com/some-big-pdf.pdf')

    # Tell the client to download the response with given filename
    headers['Content-Disposition'] = 'attachment; filename="some-big-pdf.pdf"'

    Net::HTTP.start(source.host, source.port) do |http|
      req = Net::HTTP::Get.new source

      http.request(req) do |res|
        self.response_body = res.read_body
      end
    end
  end
end

Edit: Of course send_data can also read from buffers:

编辑:当然send_data也可以从缓冲区中读取:

http.request(req) do |res|
  send_data res.read_body, filename: 'some-big-pdf.pdf', disposition: 'download'
end

However, be aware that this will tie up a worker process until complete. You should ensure that you have enough workers to handle simultaneous downloads. You may also want to look into doing this upstream within your webserver (NGINX?) rather than inside Rails.

但是,请注意,这将占用工作进程直到完成。您应该确保有足够的工作人员来处理同时下载。您可能还想在Web服务器(NGINX?)而不是Rails内部进行上游调查。

See Net::HTTP#read_body and ActionController::Metal#response_body= for more details on these methods. See also https://coderwall.com/p/kad56a/streaming-large-data-responses-with-rails

有关这些方法的更多详细信息,请参阅Net :: HTTP #read_body和ActionController :: Metal#response_body =。另见https://coderwall.com/p/kad56a/streaming-large-data-responses-with-rails