Phoenix LiveView has an amazing documentation on implementing direct upload to S3 in the official documentation. It works well when you use AWS S3. However, you might also use it with AWS S3 alternatives like Backblaze and Cloudflare R2 that is S3 API compatible.
When attempting to follow the guide above in the Phoenix LiveView documentation, you’ll quickly realize following the steps doesn’t end up with a working solution. You’ll face some CORS issue.
Then, you update the CORS configuration in the cloud storage settings and expecting it work.
But it doesn’t either.
Problem
So, what went wrong?
It turns out that most of the AWS S3 alternatives aren’t completely S3 API compatible. While they support most of the S3 API, there are always some caveats.
In our case, it’s because the documentation implement direct upload to S3 through
the POST
method with native HTML form to a presigned URL, which is currently not
supported in some of the AWS S3 alternatives like Cloudflare R2 and Backblaze.
For Cloudflare R2, the reasoning can be found under the “Supported HTTP methods” section of the Cloudflare R2 Presigned URLs documentation:
…
POST
, which performs uploads via native HTML forms, is not currently supported.
For Backblaze, while the documentation doesn’t point it out explicitly about this, it’s actually mentioned in one of the ElixirForum dicussion about Backblaze and Phoenix LiveView Uploads:
… B2 does not support POST for the S3 PutObject operation.
If we take a look at the S3 Put Object documentation for Backblaze here, it does say that the
HTTP method expected is PUT
:
…
PUT
https://s3..backblazeb2.com/:bucket/:key
To conclude, it doesn’t work because, in the Phoenix LiveView official documentation,
it is using the POST
method to upload the file directly to AWS S3, which isn’t supported by these providers.
Solution
To resolve the above issue, we have to:
- Generate the presigned URL with
PUT
method. In the documentation, it’s generating aPOST
presigned URL underneath. - Update the
Uploader
JavaScript implementation to make aPUT
HTTP requests instead ofPOST
with form.
Now, these information should be sufficient for you to resolve your bug. If not, you can refer the following for code examples from ElixirForum:
(376 words)