2014-12-03 11 views
6

Errore strano.API di archiviazione di Google - Upload ripristinabile, AJAX, errore CORS

Quando un utente desidera caricare un file, invia una richiesta AJAX al mio server. Il mio server esegue l'autenticazione lato server con OAuth2 ai server di Google, crea un token di accesso, avvia un caricamento ripristinabile e passa l'URI di caricamento ripristinabile e il token di accesso al browser.

Quindi, il browser viene caricato direttamente su Google Storage.

Tutto sembra andare bene. Il file arriva al bucket di archiviazione senza problemi, ma sto ancora ricevendo un errore CORS su Chrome e non sono sicuro di dove o perché. Ecco una versione semplificata del mio codice javascript:

var file = document.getElementById("fileInput").files[0]; 

var request = requestUpload(); 
var token = request.token; 
var uri = request.uri; 

var r = new XMLHttpRequest(); 
r.open('PUT', uri, true); 
r.setRequestHeader("Authorization", "Bearer "+token); 
r.send(file);` 

Abbastanza semplice-ma sto ancora ricevendo questo errore comune:

XMLHttpRequest cannot load https://www.googleapis.com/upload/storage/v1/b/*****. No 'Access-Control-Allow-Origin' header is present on the requested resource.

Nonostante il fatto che sembra essere completamente funzionale. Il Javascript sta chiedendo di vedere qualcosa che non sono autorizzato a fare in modo predefinito? Mi piacerebbe non avere errori.

L'oggetto XMLHttpRequest attiva anche un evento di errore dopo che è stato completato il caricamento di tutto. Sto indovinando che la richiesta si aspetta un qualche tipo di feedback da Google che non sta ottenendo e JavaScript sta diventando il latino di JavaScript, quindi la maggior parte della discussione che ho trovato riguarda jQuery.

Grazie mille!

risposta

4

Mi sono imbattuto in questo esatto problema. Mi sono fatto grattarmi la testa per un po ', ma ho trovato una soluzione. E 'abbastanza poco documentata, e il comportamento non esattamente ha senso, ma se si guarda l'ultimo punto in questa pagina

https://cloud.google.com/storage/docs/cross-origin

When using the resumable upload protocol, the Origin from the first (start upload) request is always used to decide the Access-Control-Allow-Origin header in the response, even if you use a different Origin for subsequent request. Therefore, you should either use the same origin for the first and subsequent requests, or if the first request has a different origin than subsequent requests, use the XML API with the CORS configuration set to *.

Quindi quello che ho fatto è stato ho aggiunto la richiesta Origin: http://example.com intestazione sulla richiesta di avvio della sessione ripristinabile dal server. In questo modo tutte le richieste del client che corrispondono all'ID di sessione di caricamento verificheranno tale origine.

L'unica cosa che trovo ancora strana è la richiesta di preflight OPTIONS effettuata dal browser (almeno per me) che permetteva di passare attraverso anche se la richiesta PUT non funzionava.

+0

Ciao @Craig, hai riscontrato questo problema sull'ultimo blocco? Se l'hai fatto, come hai risolto ?: http://stackoverflow.com/questions/34832640/google-storage-doesnt-send-cors-headers-for-final-chunk-in-resumable-upload – janesconference

1

Anche con questa configurazione durante l'esecuzione gsutil cors get gs://your-bucket, è necessario avviare la richiesta POST iniziale in base alla risposta @ Craig s':

[{"maxAgeSeconds": 3600, "method": ["GET", "PUT", "POST", "HEAD", "DELETE"], "origin": ["*"], "responseHeader": ["*"]}].

Utilizzando ad esempio golang è facile passare il numero Origin alla richiesta gcloud. Avendo un input r http.Request, è possibile eseguire r.Header.Get("Origin") e passarlo a una funzione che chiama il POST su gcloud. Questa è una funzione che ho scritto facendo questo in golang:

func GetUploadURL(bucket, object, contentType, origin string, expires time.Time) (string, error) { 
    url, err := storage.SignedURL(bucket, object, &storage.SignedURLOptions{ 
     GoogleAccessID: "[email protected]", 
     PrivateKey:  pkey, // set this in package init() function 
     Method:   http.MethodPost, 
     Expires:  expires, 
     ContentType: contentType, 
     Headers:  []string{"x-goog-resumable:start"}, 
    }) 

    if err != nil { 
     return "", err 
    } 

    req, err := http.NewRequest("POST", url, nil) 
    if err != nil { 
     return "", err 
    } 
    req.Header.Set("Content-Type", contentType) 
    req.Header.Set("x-goog-resumable", "start") 
    req.Header.Set("Origin", origin) 

    resp, err := http.DefaultClient.Do(req) 
    if err != nil { 
     return "", err 
    } 
    defer resp.Body.Close() 
    return resp.Header.Get("Location"), nil 
} 
Problemi correlati