雖然阿里云 OSS 與 AWS S3 兼容,但需要使用阿里云的特定端點進行配置。CarrierWave 是一個流行的 Ruby 文件上傳庫,可以方便地與 AWS S3 集成。以下是配置和使用方法:
1. 安裝必要的 gem
首先,在 Gemfile 中添加以下 gem:
gem 'carrierwave'
gem 'aws-sdk-s3'
然后運行?bundle install
。
2. 配置 CarrierWave
創建上傳器
運行生成器創建上傳器:
rails generate uploader Avatar
配置 AWS S3
在?config/initializers/carrierwave.rb
?中添加以下配置:
CarrierWave.configure do |config| config.fog_credentials = {provider: 'AWS', # 必填aws_access_key_id: ENV['AWS_ACCESS_KEY_ID'], # 推薦使用環境變量aws_secret_access_key: ENV['AWS_SECRET_ACCESS_KEY'], # 推薦使用環境變量region: 'cn-hangzhou', # 如 'us-east-1'host: ENV['AWS_HOST'], # 可選,自定義端點endpoint: ENV['AWS_ENDPOINT'], # 可選,用于兼容S3的服務path_style: false, # 設為 false 使用虛擬托管式訪問aws_signature_version: 4}config.fog_directory = ENV['AWS_BUCKET'] # 存儲桶名稱config.fog_public = false # 默認文件權限config.fog_attributes = { 'Cache-Control' => "max-age=#{365.day.to_i}" }# 可選:使用存儲桶的子目錄config.fog_path_prefix = "uploads"
end
3. 在模型中使用上傳器
假設你有一個?User
?模型需要上傳頭像:
class User < ApplicationRecordmount_uploader :avatar, AvatarUploader
end
4. 上傳器配置示例
在?app/uploaders/avatar_uploader.rb
?中:
class AvatarUploader < CarrierWave::Uploader::Base# 選擇存儲類型storage :fog # 使用 AWS S3# 覆蓋存儲目錄def store_dir"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"end# 添加白名單擴展名def extension_whitelist%w(jpg jpeg gif png)end# 覆蓋文件名def filename"#{secure_token}.#{file.extension}" if original_filename.present?endprotecteddef secure_tokenvar = :"@#{mounted_as}_secure_token"model.instance_variable_get(var) || model.instance_variable_set(var, SecureRandom.uuid)end
end
5. 在視圖中使用
表單中使用文件字段:
<%= form_for @user do |f| %><%= f.file_field :avatar %><%= f.submit %>
<% end %>
顯示上傳的文件:
<%= image_tag @user.avatar.url if @user.avatar? %>
6. 處理大文件
對于大文件上傳,你可能需要:
# 在 config/initializers/carrierwave.rb 中
config.fog_attributes = {'x-amz-meta-uploaded-by' => 'my-app','Cache-Control' => 'max-age=315576000'
}
7. 測試環境配置
在測試環境中,你可能想使用本地存儲:
# config/environments/test.rb
config.carrierwave.storage = :file
config.carrierwave.enable_processing = false
?
解決 AWS SDK 上傳到阿里云 OSS 的 403 Forbidden 錯誤
你遇到的?SignatureDoesNotMatch
?錯誤表明 AWS SDK 生成的簽名與阿里云 OSS 期望的簽名不匹配。這是使用 AWS SDK 訪問阿里云 OSS 時的常見問題,因為阿里云 OSS 雖然兼容 S3 協議,但在簽名計算上有一些差異。
增加 CarrierWave 配置
# 在 config/initializers/carrierwave.rb 中
config.fog_credentials = {#...path_style: true, # 注意這里是 path_style 而不是 force_path_styleaws_signature_version: 4 # 注意參數名是 aws_signature_version 而不是 signature_version
}
但是還是不能完美解決阿里云 OSS 的?SignatureDoesNotMatch
?問題。
當您在 CarrierWave 配置中添加:
aws_signature_version: 4
時,fog-aws 內部仍然會強制使用?service: 's3'
,這就是導致簽名不匹配的根本原因。
解決方案:
如果您必須使用 fog-aws,可以通過猴子補丁修改:
# 在 config/initializers/carrierwave.rb 中添加以下補丁
module Fogmodule AWSclass SignatureV4# 重寫初始化方法,強制指定service為'oss'def initialize(aws_access_key_id, secret_key, region, service)@region = region@service = 'oss' # 強制覆蓋為oss,原參數service被忽略@aws_access_key_id = aws_access_key_id@hmac = Fog::HMAC.new('sha256', 'AWS4' + secret_key)endendend
end
?