19

Tôi đang sử dụng CloudFlare CDN trên ứng dụng Rails 3.1 của mình. Cloudflare là một CDN hoạt động ở cấp DNS. Trong lần truy cập đầu tiên vào một nội dung tĩnh, CloudFlare tải nó từ ứng dụng của bạn rồi lưu nó vào CDN của họ. Yêu cầu trong tương lai cho tải nội dung đó từ CDN thay vì ứng dụng của bạn.Làm cách nào để ngăn Rails 3.1 khỏi việc lưu vào bộ nhớ đệm các tài sản tĩnh tới Rails.cache?

Vấn đề tôi đang gặp là rằng nếu bạn đặt bộ điều khiển bộ nhớ đệm là true:

config.action_controller.perform_caching = true 

nó cho phép các middleware Kệ :: Cache. Vì Rails đặt một thiết lập kiểm soát bộ nhớ cache mặc định cho các tài sản tĩnh, các tài sản đó được ghi vào kho lưu trữ Rails.cache. Kết quả là lưu trữ bộ nhớ cache của tôi (trong trường hợp của tôi redis) đang được lấp đầy với các tài sản tĩnh với url là khóa băm.

Thật không may, tôi không thể tắt tiêu đề kiểm soát bộ nhớ cache nội dung tĩnh mà không ảnh hưởng đến cách trình duyệt Cloudflare và trình duyệt của người dùng của tôi lưu trữ nội dung. Tôi không thể tắt bộ nhớ đệm của bộ điều khiển hoặc tôi mất bộ nhớ đệm trang/hành động/đoạn. Cùng một kết quả nếu tôi xóa Rack :: Cache middleware.

Có ai có ý tưởng nào khác không?

Cập nhật: Tôi đã mở một vé trên GitHub here.

+0

Khi bạn nói nội dung tĩnh, bạn có nghĩa là chỉ các tệp mà Sprockets tạo ra? –

+0

Vâng, tôi có. Với hàm băm được thêm vào tên tệp. –

Trả lời

7

Áp phích gốc muốn ngăn chặn nội dung tĩnh xâm nhập vào bộ nhớ cache Rails chung, điều này khiến họ muốn vô hiệu hóa Rack :: Cache. Thay vì làm điều này, giải pháp tốt hơn là định cấu hình Rack :: Cache để sử dụng bộ nhớ cache riêng biệt hơn bộ nhớ cache Rails chung.

Rack :: Cache nên được định cấu hình khác nhau cho lưu trữ thực thể so với lưu trữ meta. Rack :: Cache có hai vùng lưu trữ khác nhau: meta và các cửa hàng thực thể. Các metastore giữ thông tin cấp cao về mỗi mục bộ nhớ cache bao gồm yêu cầu HTTP và các tiêu đề phản hồi. Khu vực này lưu trữ các khối dữ liệu nhỏ được truy cập ở tần số cao. Cửa hàng thực thể lưu trữ nội dung của nội dung phản hồi có thể là lượng dữ liệu tương đối lớn mặc dù dữ liệu được truy cập ít thường xuyên hơn so với metastore.

Cấu hình bên dưới lưu trữ thông tin di chuyển trong memcached nhưng phần nội dung thực của nội dung vào hệ thống tệp.

Sử dụng đá quý memcached:

config.action_dispatch.rack_cache = { 
    :metastore => 'memcached://localhost:11211/meta', 
    :entitystore => 'file:tmp/cache/rack/body', 
    :allow_reload => false 
} 

Sử dụng Dalli đá quý

config.action_dispatch.rack_cache = { 
    :metastore => Dalli::Client.new, 
    :entitystore => 'file:tmp/cache/rack/body', 
    :allow_reload => false 
} 

Bằng cách cấu hình này là sự giới thiệu cho Heroku: https://devcenter.heroku.com/articles/rack-cache-memcached-static-assets-rails31

8

Sau rất nhiều thử nghiệm, tôi đã kết thúc làm điều này trong cấu hình của tôi/application.rb:

if !Rails.env.development? && !Rails.env.test? 
    config.middleware.insert_before Rack::Cache, Rack::Static, urls: [config.assets.prefix], root: 'public' 
end 

Điều này không là thêm một Rack :: tĩnh giá trung trước khi yêu cầu rack :: Cache. Rack :: Static middleware phục vụ các url với một tiền tố phù hợp với một thư mục gốc. Ở đây tôi đang cung cấp config.assets.prefix làm tiền tố url của tôi mặc định là '/ asset'. Tôi đang đặt thư mục gốc thành thư mục 'công khai'.

Yêu cầu con đường này:

/assets/jquery-e8da439bbc8fd345e34ac57c6a216318.min.js

nên tìm thấy nó trong tập tin này:

công cộng/tài sản/jquery-e8da439bbc8fd345e34ac57c6a216318.min .js

Điều này sẽ phân phối bất kỳ nội dung nào trực tiếp ra khỏi thư mục công khai/tài sản thay vì nhấn Rails :: Ca tất cả, điều này sẽ ngăn không cho nó lưu trữ các tài sản trong kho lưu trữ Rails cache_store. Điều này sẽ chỉ hoạt động nếu bạn chạy 'tài sản cào: biên dịch trước' trong sản xuất, nếu không sẽ không có tài sản biên dịch trước trong 'công khai/tài sản'.

+0

một cách ngẫu nhiên sang một bên - làm thế nào để bạn nhận được ID nội dung của mình để hiển thị trong tên tệp? – Kevin

+0

Bạn đã đặt 'config.assets.precompile' để bao gồm tất cả các tệp bạn muốn biên dịch trước chưa? –

+0

@Kevin bạn có thể đặt 'config.action_controller.perform_caching = true' trong production.rb http://guides.rubyonrails.org/asset_pipeline.html#in-production – Schneems

1

Một cách khác để giải quyết cùng một vấn đề và vấn đề này là sử dụng ActionDispatch :: tĩnh middleware thay vì rack :: tĩnh như thế này:

if !Rails.env.development? && !Rails.env.test? 
    config.middleware.insert_before Rack::Cache, ::ActionDispatch::Static, 'public', config.static_cache_control 
end 

sự khác biệt giữa Kệ :: tĩnh và ActionDispatch là gì: : Tĩnh bạn hỏi?

  • Rack :: Static lấy một mảng tiền tố url để kiểm tra url yêu cầu. Vì vậy, trong trường hợp của chúng tôi, nó sẽ chỉ kiểm tra các tập tin nếu đường dẫn yêu cầu bắt đầu bằng '/ assets'.

  • ActionDispatch :: Tĩnh sẽ kiểm tra sự tồn tại của tệp trong 'công khai' trên mọi yêu cầu GET/HEAD, bất kể đường dẫn.

  • Rack :: Static không kiểm tra tệp trước, nó gọi Rack :: File.new trên tệp, vì vậy nếu nó không tồn tại, nó sẽ trả về 404, nó sẽ không chuyển yêu cầu xuống chuỗi trung gian.

  • Nếu ActionDispatch :: Tĩnh không tìm thấy tệp trong đường dẫn của nó, nó sẽ tiếp tục xuống chuỗi giá trung gian (phần còn lại của ngăn xếp Rails).

Cuối cùng, bất kỳ ActionDispatch :: tĩnh nào không tìm thấy trong 'công khai', nó sẽ chỉ chuyển xuống ngăn xếp Rails. Vì vậy, Rails sẽ kết thúc phục vụ các tài sản mà ActionDispatch :: Tĩnh không thể tìm thấy. Điều này giải quyết vấn đề của tôi về tài sản không được tìm thấy bởi Rack :: Cache, nhưng nó cũng là nguồn tài nguyên nhiều hơn kể từ khi mọi yêu cầu sẽ kích hoạt một kiểm tra tập tin.

+0

Khi bạn nói" mọi yêu cầu sẽ kích hoạt kiểm tra tệp " - bạn có nghĩa là mọi yêu cầu cho ứng dụng hoặc chỉ yêu cầu công khai? –

+0

Ngoài ra, trong điểm bullet đầu tiên, bạn có ý nói ActionDispatch :: Static không? –

+1

Không đúng. Rack :: Static lấy một mảng các tiền tố url. Họ thậm chí còn được gọi là "url". –

3

Bạn có thể tắt bộ nhớ đệm của đường ống dẫn tài sản các tệp trong khi rời khỏi bộ nhớ đệm khác tại chỗ với:

config.assets.cache_store = :null_store 

Điều đó sẽ giữ cho Sprockets khỏi bộ nhớ đệm bất cứ thứ gì.

+0

Điều này làm việc cho tôi trên Rails 3.2 sau khi tất cả các câu trả lời ở trên chỉ cho tôi nửa chừng ở đó. Cảm ơn! –

Các vấn đề liên quan