Direct downloads from Google Cloud Storage and how to set up CORS
Opened this issue · 0 comments
Leaving this here for posterity, I got slogged with this one.
In order to direct download files from GCS you need a couple of things:
- A valid signed URL to your cloud storage object
- A valid CORS configuration installed in your bucket
I am using the official google cloud storage php library to generate signed URLs: https://github.com/googleapis/google-cloud-php-storage so check their docs for that.
In order to install your cors configuration you'll need to install gsutil: https://cloud.google.com/storage/docs/gsutil and use the below gsutil cors
command:
gsutil cors set path/to/cors.json your-bucket-name
with the contents of your cors.json file looking like this:
[
{
"origin": ["https://domain1.com/"],
"method": ["GET"],
"responseHeader": ["*"],
"maxAgeSeconds": 3600
},
{
"origin": ["https://www.domain.com/"],
"method": ["GET"],
"responseHeader": ["*"],
"maxAgeSeconds": 3600
},
{
"origin": ["https://staging.domain.com/"],
"method": ["GET"],
"responseHeader": ["*"],
"maxAgeSeconds": 3600
}
]
(It's a good idea to put all your dev and prod urls in there).
Then in your app, serve the signed url somehow and use axios and js-file-download to download the file as per the readme in this repo:
axios.get(signedUrl, {
responseType: 'blob',
}).then(res => {
fileDownload(res.data, filename)
}).catch(error => reject(error))
ALSO
In my UI I have a loading spinner that relies on the promise provided by axios there, and that promise resolves too early - there is a lag between when the promise resolves and when the file download actually starts, meaning my UI says "all done!" and then nothing happens until the blob finishes downloading. To get around this, I pass a function in as the filename
to the fileDownload
call:
}).then(res => {
fileDownload(res.data, filename()) // <-- here
that function returns a string for the filename, but first it manually flicks the UI over to the next step. full example:
const loading = false
const filename = 'some-supplied-string.mp4'
function resolveFilename(){
loading = false
return filename
}
function downloadFile(){
loading = true
axios.get('/fetch-signed-url').then(response => {
axios.get(response.data.signedUrl, {
responseType: 'blob',
}).then(response => {
fileDownload(res.data, resolveFilename())
})
})
}
Hope that helps someone!