2012-09-05 32 views
26

Tôi có ứng dụng Rails được lưu trữ trên Heroku. Ứng dụng tạo và lưu trữ các tệp PDF trên Amazon S3. Người dùng có thể tải xuống các tệp này để xem trong trình duyệt của họ hoặc để lưu trên máy tính của họ.Đường ray: cho phép tải xuống các tệp được lưu trữ trên S3 mà không hiển thị URL S3 thực tế cho người dùng

Sự cố tôi gặp phải là mặc dù việc tải xuống các tệp này có thể thông qua URL S3 (như "https://s3.amazonaws.com/my-bucket/F4D8CESSDF.pdf"), rõ ràng KHÔNG phải là cách tốt để làm điều đó. Nó không phải là mong muốn để tiếp xúc với người dùng rất nhiều thông tin về phụ trợ, chưa kể đến các vấn đề an ninh tăng lên.

Có thể ứng dụng của tôi bằng cách nào đó truy xuất dữ liệu tệp từ S3 trong bộ điều khiển, sau đó tạo luồng tải xuống cho người dùng, sao cho URL Amazon không được hiển thị?

+0

Bạn rõ ràng có thể tải nó và sau đó dòng nó trở lại cho người sử dụng nhưng nó sẽ không được đặc biệt nhanh. –

Trả lời

9

Có, điều này là có thể - chỉ cần tìm nạp tệp từ xa bằng Rails và lưu trữ tạm thời trên máy chủ của bạn hoặc lưu nó trực tiếp từ bộ đệm. Vấn đề với điều này là tất nhiên thực tế là bạn cần phải lấy tập tin đầu tiên trước khi bạn có thể phục vụ nó cho người dùng. Xem this thread để thảo luận, giải pháp của họ giống như sau:

#environment.rb 
require 'open-uri' 

#controller 
def index 
    data = open(params[:file]) 
    send_data data, :filename => params[:name], ... 
end 

This issue is also somewhat related.

+0

Điều này hóa ra lại đơn giản, cảm ơn bạn. Đây là triển khai thực tế của tôi: def tải xuống file_name = params ["file_id"] + ".pdf" dữ liệu = mở ("https://s3.amazonaws.com/#{ENV['S3_BUCKET_NAME']}/ # {file_name} ") dữ liệu send_data.read,: filename => file_name,: type =>" application/pdf ",: disposition => 'attachment', : stream => 'true',: buffer_size => ' 4096 ' kết thúc Tôi đã chấp nhận giải pháp của bạn làm giải pháp cho vấn đề này vì đây là giải pháp đơn giản nhất để triển khai. – futureshocked

+0

Một của Serge cũng tốt, với lợi ích của việc phát hành ứng dụng Rails từ việc xử lý tải xuống, nó chỉ cần thêm một chút công việc để làm cho nó hoạt động. – futureshocked

+0

Chỉ những người khác biết, có hai vấn đề với điều này tôi tìm thấy: 1) Nó tải xuống máy chủ và sau đó cho người dùng, có thể mất một lúc; và 2) Trải nghiệm cho người dùng không phải là điều họ mong đợi. Thay vào đó, thay vì tải xuống trong trình duyệt của họ, có vẻ như nó đang tải thứ gì đó. Hãy xem http://stackoverflow.com/a/23161355/293280 để biết thêm thông tin. –

51

Bạn có thể tạo các đối tượng s3 của mình dưới dạng riêng tư và tạo các url công khai tạm thời cho chúng bằng phương thức url_for (đá quý aws-s3). Bằng cách này, bạn không truyền tệp qua máy chủ ứng dụng của mình, có khả năng mở rộng hơn. Nó cũng cho phép đặt quyền dựa trên phiên (ví dụ: đưa ra trong ứng dụng của bạn), theo dõi các sự kiện tải xuống, v.v.

Để thay đổi liên kết trực tiếp thành tệp được lưu trữ thành các liên kết đến bộ điều khiển/hành động tạo url tạm thời và chuyển hướng đến nó. Như thế này:

class HostedFilesController < ApplicationController 

    def show 
    s3_name = params[:id] # sanitize name here, restrict access to only some paths, etc 
    AWS::S3::Base.establish_connection!(...) 
    url = AWS::S3::S3Object.url_for(s3_name, YOUR_BUCKET, :expires_in => 2.minutes) 
    redirect_to url 
    end 

end 

Ẩn tên miền amazon trong url tải xuống thường được thực hiện với DNS aliasing. Bạn cần phải create CNAME record aliasing your subdomain, ví dụ: downloads.mydomain, đến s3.amazonaws.com. Sau đó, bạn có thể chỉ định tùy chọn :server trong AWS::S3::Base.establish_connection!(:server => "downloads.mydomain", ...) và đá quý S3 sẽ sử dụng nó để tạo liên kết.

+0

Serge, tôi đã thử phương pháp của bạn. Nó hoạt động, tuy nhiên URL trông như thế này: http://s3.amazonaws.com/my-bucket/F4D8CED0.pdf?AWSAccessKeyId=my-actual-key&Expires=1346904098&Signature=Wo7wYH6Ek%2FBot3wd2xYbGt4ybSU%3D. Những gì tôi muốn thấy lý tưởng là không có đề cập đến amazon, nhưng một cái gì đó như "http://mydomain.com/download/file.pdf. Điều này có thể không? – futureshocked

+0

Bạn có thể nhận được khá gần với điều đó với CNAME, nhưng nó sẽ giống như 'something.mydomain.com/path/file.pdf'. Tôi đã cập nhật câu trả lời để phản ánh điều đó –

+0

Giải pháp rất hay, cám ơn Serge. – futureshocked

-1

Trước tiên, bạn cần tạo CNAME trong miền của mình, như giải thích here.

Thứ hai, bạn cần tạo một nhóm có cùng tên mà bạn đặt trong CNAME.

Và để kết thúc bạn cần thêm các cấu hình này trong cấu hình của bạn/initializers/carrierwave.rb:

CarrierWave.configure do |config| 
    ... 
    config.asset_host   = 'http://bucket_name.your_domain.com' 
    config.fog_directory  = 'bucket_name.your_domain.com' 
    ... 
end 
Các vấn đề liên quan