使用 shrine 和 aws-sdk 上传到 digitalocean 空间时出错
error on uploading to digitalocean spaces using shrine and aws-sdk
我正在使用 shrine 直接上传到 aws-s3
存储桶并且工作正常。现在我想改用 DigitalOcean spaces
。所以我改变了一些神社的设置,如下所示(只改变了与空间相关的 env
变量)。
require "shrine"
require "shrine/storage/s3"
s3_options = {
access_key_id: ENV["SPACES_ACCESS_KEY_ID"],
secret_access_key: ENV["SPACES_SECRET_ACCESS_KEY"],
region: ENV["SPACES_REGION"],
bucket: ENV["SPACES_BUCKET"],
endpoint: ENV["SPACES_ENDPOINT"]
}
Shrine.storages = {
cache: Shrine::Storage::S3.new(prefix: "cache", upload_options: {acl: "public-read"}, **s3_options),
store: Shrine::Storage::S3.new(prefix: "store", upload_options: {acl: "public-read"}, **s3_options),
}
Shrine.plugin :activerecord
Shrine.plugin :presign_endpoint
Shrine.plugin :restore_cached_data
Shrine.plugin :backgrounding
Shrine::Attacher.promote {|data| UploadJob.perform_async(data)}
Shrine::Attacher.delete {|data| DeleteJob.perform_async(data)}
我还在空格中添加了 cors 以允许如下所有请求
但是当我上传时出现这个错误。
<Error><Code>AccessDenied</Code><Message>Policy missing condition: Content-Type</Message><BucketName>testing-dev</BucketName><RequestId>tx0000000036366363370-3663t37373-33883-sgp1a</RequestId><HostId>349494-sgp1a-sgp</HostId></Error>
这可能是什么问题?我可以看到策略中缺少告诉 content-type
的错误。但如果是这样,我该如何添加呢?
我发现解决方案是手动添加 contentType
。
所以我这样更新
Shrine.storages = {
cache: Shrine::Storage::S3.new(prefix: "cache", upload_options: {acl: "public-read", content_type: "png/jpeg"}, **s3_options),
store: Shrine::Storage::S3.new(prefix: "store", upload_options: {acl: "public-read", content_type: "png/jpeg"}, **s3_options),
}
我不知道这是最好的方法,因为它会根据 mime type
自动设置 contentType
,并且在上传到亚马逊 s3
时可以正常工作。但不知何故,这不适用于 digitalocean
。所以我们必须像这样手动指定以使其与空格一起使用。
似乎 DigitalOcean Spaces 现在要求预签名政策包含 contentType
条件。预签名策略是在预签名端点中生成的,因此您可以告诉它根据 filename
查询参数添加 :content_type
:
Shrine.plugin :presign_endpoint, presign_options: -> (request) do
filename = request.params["filename"]
extension = File.extname(filename)
content_type = Rack::Mime.mime_type(extension)
{ content_type: content_type }
end
这应该使 :content_type
始终存在,因为如果 filename
没有扩展名或扩展名无法识别,Rack::Mime.mime_type
将 return application/octet-stream
,这是 S3 默认分配给对象的内容类型。
只需确保在发送预签名请求时在客户端传递 filename
查询参数。例如。使用 window.fetch
它将是:
fetch('/presign?filename=' + file.name)
我正在使用 shrine 直接上传到 aws-s3
存储桶并且工作正常。现在我想改用 DigitalOcean spaces
。所以我改变了一些神社的设置,如下所示(只改变了与空间相关的 env
变量)。
require "shrine"
require "shrine/storage/s3"
s3_options = {
access_key_id: ENV["SPACES_ACCESS_KEY_ID"],
secret_access_key: ENV["SPACES_SECRET_ACCESS_KEY"],
region: ENV["SPACES_REGION"],
bucket: ENV["SPACES_BUCKET"],
endpoint: ENV["SPACES_ENDPOINT"]
}
Shrine.storages = {
cache: Shrine::Storage::S3.new(prefix: "cache", upload_options: {acl: "public-read"}, **s3_options),
store: Shrine::Storage::S3.new(prefix: "store", upload_options: {acl: "public-read"}, **s3_options),
}
Shrine.plugin :activerecord
Shrine.plugin :presign_endpoint
Shrine.plugin :restore_cached_data
Shrine.plugin :backgrounding
Shrine::Attacher.promote {|data| UploadJob.perform_async(data)}
Shrine::Attacher.delete {|data| DeleteJob.perform_async(data)}
我还在空格中添加了 cors 以允许如下所有请求
但是当我上传时出现这个错误。
<Error><Code>AccessDenied</Code><Message>Policy missing condition: Content-Type</Message><BucketName>testing-dev</BucketName><RequestId>tx0000000036366363370-3663t37373-33883-sgp1a</RequestId><HostId>349494-sgp1a-sgp</HostId></Error>
这可能是什么问题?我可以看到策略中缺少告诉 content-type
的错误。但如果是这样,我该如何添加呢?
我发现解决方案是手动添加 contentType
。
所以我这样更新
Shrine.storages = {
cache: Shrine::Storage::S3.new(prefix: "cache", upload_options: {acl: "public-read", content_type: "png/jpeg"}, **s3_options),
store: Shrine::Storage::S3.new(prefix: "store", upload_options: {acl: "public-read", content_type: "png/jpeg"}, **s3_options),
}
我不知道这是最好的方法,因为它会根据 mime type
自动设置 contentType
,并且在上传到亚马逊 s3
时可以正常工作。但不知何故,这不适用于 digitalocean
。所以我们必须像这样手动指定以使其与空格一起使用。
似乎 DigitalOcean Spaces 现在要求预签名政策包含 contentType
条件。预签名策略是在预签名端点中生成的,因此您可以告诉它根据 filename
查询参数添加 :content_type
:
Shrine.plugin :presign_endpoint, presign_options: -> (request) do
filename = request.params["filename"]
extension = File.extname(filename)
content_type = Rack::Mime.mime_type(extension)
{ content_type: content_type }
end
这应该使 :content_type
始终存在,因为如果 filename
没有扩展名或扩展名无法识别,Rack::Mime.mime_type
将 return application/octet-stream
,这是 S3 默认分配给对象的内容类型。
只需确保在发送预签名请求时在客户端传递 filename
查询参数。例如。使用 window.fetch
它将是:
fetch('/presign?filename=' + file.name)