How use Object URL to Upload a file by Javascrpt?
I created an endpoint in my Backend where I securely generate a URL to upload a file, according to the API doc: https://developers.linode.com/api/v4/object-storage-buckets-cluster-id-bucket-object-url/#post
I'am using this javascript code to upload file from my browser:
handleUpload = async e => {
const file = e.target.files[0];
if (!file) return;
const payload = await fetch(`${MY_API}/s3/direct_post`).then(res =>
res.json()
);
const url = payload.url;
const formData = new FormData();
formData.append('file', file);
const xml = await fetch(url, {
method: 'PUT',
body: formData
}).then(res => res.text());
console.log('RESULT = ', xml);
};
However, it results in a CORS problem:
<img alt="Image" src="https://image.prntscr.com/image/sSgiYg3bS6Sff8dVbRrUHw.png">
When I try to use Postman to upload the image, it results in the following problem:
<?xml version="1.0" encoding="UTF-8"?>
<Error>
<Code>SignatureDoesNotMatch</Code>
<RequestId>tx000000000000001eeca5f-005e6065ee-d8efda-default</RequestId>
<HostId>d8efda-default-default</HostId>
</Error>
3 Replies
Based on this GitHub issue, it looks like there may be an extra HTTPS header included that is affecting the signature. You'll also want to make sure you're using the correct API endpoint for your bucket, i.e. https://api.linode.com/v4/object-storage/buckets/us-east-1/example-bucket/object-url
. Postman is not held to the same CORS standards, which explains why you're getting a different message when using it. There's some information here that can help with the SignatureDoesNotMatch
issue.
Hi @jyoo
Thank you for your help. I was able to solve the problem using the axios
:
async function handleUpload(e){
const file = e.target.files[0];
if (!file) return;
const payload = await fetch(`${MY_API}/s3/direct_post`).then(res =>
res.json()
);
const url = payload.url;
var options = {
headers: {
'Content-Type': 'image/png'
}
};
return axios.put(url, file, options);
}
And in my Ruby server endpoint with this:
def s3_url
RestClient.log = STDOUT
begin
url = "https://api.linode.com/v4/object-storage/buckets/us-east-1/#{ENV['LINODE_BUCKET']}/object-url"
res = RestClient.post(url,
{
method: 'PUT',
name: 'file.png',
content_type: 'image/png'
}.to_json,
{
Authorization: "Bearer #{ENV['LINODE_TOKEN']}",
content_type: :json
}
)
res_json = JSON.parse( res.body )
render json: res_json
rescue RestClient::ExceptionWithResponse => e
render json: {
error: e.response
}, status: 422
end
end
However, I would like to make these files publicly available, for example, that I could access as follows:
https://us-east-1.linodeobjects.com/LINODE_BUCKET/file.png
I've tried to make my Bucket public using s3cmd (s3cmd setacl s3://LINODE_BUCKET --acl-public
) but even so the file is not public.
Do you know if there is any way to do this without having to generate a signed URL?
Hello, your issue seems very similar to my recent question here:
Have you found a solution to your issue of making the file public?