2014-09-05 9 views
7

Ho implementato caricamenti ripristinabili basati su browser nel Cloud Storage di Google utilizzando un XMLHttpRequest inviato a un URL di caricamento ripristinabile creato sul lato server. Funziona perfettamente quando disabilita la sicurezza web, cosa che ho fatto durante lo sviluppo.XMLHttpRequest CORS a Google Cloud Storage funzionante solo nella richiesta di preflight

Ma ora nel mondo reale, CORS continua a creare problemi. Ho provato questo con altri browser (senza successo), ma sono rimasto incollato al chrome per ulteriori test.

Nota: Una voce fake.host in /etc/HOSTS viene utilizzata per ingannare chrome in modo da evitare restrizioni localhost. Tuttavia, lo stesso accade con il dominio "reale" del nostro server di test online.

La richiesta viene avviato utilizzando una normale chiamata XMLHttpRequest:

var xhr = this.newXMLHttpRequest(); 
xhr.open('PUT', url, true); 

xhr.setRequestHeader('Content-Type', this.currentInputFile.type); 
xhr.setRequestHeader('Content-Range', 'bytes ' + startByte + '-' + (this.currentInputFile.size - 1) + '/' + this.currentInputFile.size); 

xhr.onload = function(e) { 
    ... 
}; 

... 

if (startByte > 0) { 
    xhr.send(this.currentInputFile.slice(startByte)); 
} else { 
    xhr.send(this.currentInputFile); 
} 

Il browser inizia quindi con successo una richiesta di verifica preliminare:

Remote Address:173.194.71.95:443 
Request URL:https://www.googleapis.com/upload/storage/v1/b/my-bucket-name/o?uploadType=resumable&name=aa%20spacetestSMALL_512kb.mp4&upload_id=XXXXXXXXX 
Request Method:OPTIONS 
Status Code:200 OK 

intestazioni di richiesta:

:host:www.googleapis.com 
:method:OPTIONS 
:path:/upload/storage/v1/b/my-bucket-name/o?uploadType=resumable&name=aa%20spacetestSMALL_512kb.mp4&upload_id=XXXXXXXXX 
:scheme:https 
:version:HTTP/1.1 
accept:*/* 
accept-encoding:gzip,deflate 
accept-language:en-US,en;q=0.8,de;q=0.6 
access-control-request-headers:content-range, content-type 
access-control-request-method:PUT 
origin:https://fake.host 
referer:https://fake.host/upload.xhtml 
user-agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.94 Safari/537.36 
x-client-data:YYYYYY 

Parametri stringa di query

uploadType:resumable 
name:aa spacetestSMALL_512kb.mp4 
upload_id:XXXXXXXXX 

risposta intestazioni

access-control-allow-credentials:true 
access-control-allow-headers:content-range, content-type 
access-control-allow-methods:PUT 
access-control-allow-origin:https://fake.host 
alternate-protocol:443:quic 
content-length:0 
content-type:text/html; charset=UTF-8 
date:Fri, 05 Sep 2014 14:11:21 GMT 
server:UploadServer ("Built on Aug 18 2014 11:58:36 (1408388316)") 
status:200 OK 
version:HTTP/1.1 

... e inizia il PUT-richiesta finché viene trasferito tutti i dati. Ma in seguito Chrome registra silenziosamente un errore senza completare/terminare la richiesta:

XMLHttpRequest non può caricare https://www.googleapis.com/upload/storage/v1/b/my-bucket-name ... XXXXXXXX. Nessuna intestazione 'Access-Control-Allow-Origin' è presente sulla risorsa richiesta. L'origine 'https://fake.host' non è quindi consentita l'accesso.

Questo è ciò che i registri cromati sulla richiesta PUT:

Request URL:https://www.googleapis.com/upload/storage/v1/b/my-bucket-name/o?uploadType=resumable&name=aa%20spacetestSMALL_512kb.mp4&upload_id=XXXXXXXXX 

intestazioni di richiesta

Provisional headers are shown 
Content-Range:bytes 0-3355302/3355303 
Content-Type:video/mp4 
Origin:https://fake.host 
Referer:https://fake.host/upload.xhtml 
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.94 Safari/537.36 
X-DevTools-Emulate-Network-Conditions-Client-Id:YYYYYYY 

stringa di query

uploadType:resumable 
name:aa spacetestSMALL_512kb.mp4 
upload_id:XXXXXXXXX 

In particolare, quando si aggiunge lo stesso URL in http://client.cors-api.appspot.com/client e il rilascio qualsiasi richiesta, tutti tranne i tipi di richiesta OPTIONS falliscono, anche. Sembra che la cloud storage api emetta solo le intestazioni di risposta corrette per le richieste OPTION, ma non le richieste PUT/POST/GET/....

Quindi sto facendo qualcosa di impossibile? C'è qualcosa di rotto? Si tratta di un bug nel cloud storage api? Ho passato ore a googling e a leggere le risposte SO, senza fortuna fino ad ora.

Per ora, potrei verificare periodicamente se il download ha trasferito il 100% dei dati e ignorare semplicemente il risultato della richiesta http, poiché il file viene infatti completamente caricato nel bucket di archiviazione. Ma questa è una brutta soluzione che non voglio davvero usare se il vero problema può essere risolto.

+0

Avete impostato su CORS sul GCS? https://cloud.google.com/storage/docs/cross-origin#Configuring-CORS-on-a-Bucket – Ryan

+0

Sì, certo. Immagino che senza di essa la richiesta di preflight fallirebbe, il che non avviene. Solo la risposta finale dopo aver caricato il file non è valida. – Roben

+0

Puoi mostrare il messaggio che hai usato? Sembra che tu dimentichi il "metodo": ["PUT", "POST", "GET"], – Ryan

risposta

3

Quando si richiede un URL di upload ripristinabile, è necessario includere l'origine del browser invierà quando si cerca di utilizzare tale URL caricati, oppure il successivo caricamento fallirà, proprio come sta accadendo in questione (le OPZIONI chiamata avere un bell'aspetto, ma il PUT no).

Deve corrispondere esattamente all'origine del browser (che è possibile ottenere come location.origin in javascript).

Questo è il passo "Avvio di una sessione di caricamento ripristinabile" in questa documentazione: https://cloud.google.com/storage/docs/json_api/v1/how-tos/resumable-upload

Se stai richiedendo l'url di upload resumable sul lato server, avrete probabilmente bisogno lato client (il browser) per trasmetterti la sua origine (es .: location.origin).

FWIW stavo usando biblioteca Cloud Storage di Google per Python per questo passaggio, e aveva bisogno di aggiungere l'origine in questo modo:

myblob.create_resumable_upload_session(mycontenttype, origin=browserorigin) 

Nota che sicuramente non è necessario configurare CORS per il secchio.

+1

Immagino che questo non fosse possibile 3 anni fa, ma ora sembra la soluzione giusta. Ci sono problemi di git del 2016 su questo problema (ad esempio https://github.com/GoogleCloudPlatform/google-cloud-node/issues/1099). Grazie! – Roben

3

Poiché questa domanda rimane senza risposta e ottiene ancora un buon numero di opinioni, cercherò di pubblicare qualcosa di definitivo qui.

Il 'Access-Control-Allow-Origin' intestazione restituito nella risposta alle eventuali richieste PUT per caricare i dati è sempre impostato al l'origin data in the initial POST request utilizzato per avviare il caricamento, come da current docs:

Quando si utilizza l'upload resumable protocollo, l'origine dalla prima richiesta (caricamento iniziale) viene sempre utilizzata per decidere l'intestazione Access-Control-Allow-Origin nella risposta, anche se si utilizza una Origine diversa per la richiesta successiva. Pertanto, è necessario utilizzare la stessa origine per la prima e le successive richieste oppure, se la prima richiesta ha un'origine diversa rispetto alle richieste successive, utilizzare l'API XML con la configurazione CORS impostata su *.

Ciò significa che è necessario inviare una richiesta POST iniziale prima che qualsiasi richiesta PUT richieda l'invio di dati e che eventuali richieste PUT successive debbano avere la stessa "origine" del POST iniziale.

Per quanto riguarda la configurazione CORS impostato in GCS, questo vale solo per le chiamate verso l'API XML, dal current docs:

Nota: configurazione CORS è valida solo per le richieste API XML. Per le richieste API JSON , Cloud Storage restituisce sempre l'intestazione Access-Control-Allow-Origin con l'origine della richiesta.

Problemi correlati