2017-12-02 109 views
8

Próbuję przesłać pliki z aplikacji Angular 4 do usługi interfejsu JSON API, która akceptuje ciągi base64 jako treść pliku.Angular - prześlij plik jako base64

Więc to, co robię, to - przeczytaj plik z FileReader.readAsDataURL, a kiedy użytkownik potwierdzi przesłanie, utworzę żądanie JSON do API i wyślę ciąg base64 pliku, który dostałem wcześniej.

To gdzie zaczyna problem - jak tylko coś zrobić z „zawartością” (log go wysłać go w/e) wniosek zostanie wysłany, ale jego szalenie wolno, na przykład 20 sekund dla pliku 2 MB.

Próbowałem:

  • użyciu ArrayBuffer i ręcznie przekształcenie go do base64
  • przechowywania ciąg base64 w HTML i pobieranie go później
  • czyta pliki po kliknięciu przez użytkownika przycisku wysyłania
  • używanie starego klienta z @angular/common
  • przy użyciu zwykłego żądania XHR

ale wszystko prowadzi do tego samego wyniku.

Wiem, gdzie leży problem. Ale dlaczego to się stało? Czy jest to coś specyficznego dla przeglądarki lub konkretnego kanciastego? Czy istnieje bardziej preferowane podejście (należy pamiętać, że musi to być łańcuch base64)?


Uwagi:

  • zmieniania czegokolwiek w API jest poza moją kontrolą
  • API jest w porządku, wysyłając dowolną listonosz plik koryta zakończy natychmiast

Kod:

Ten sposób działa, gdy użytkownik dodaje plik do zrzutowiska:

public onFileChange(files: File[]) : void { 
    files.forEach((file: File, index: number) => { 
     const reader = new FileReader; 

     // UploadedFile is just a simple model that contains filename, size, type and later base64 content 
     this.uploadedFiles[index] = new UploadedFile(file); 

     //region reader.onprogress 
     reader.onprogress = (event: ProgressEvent) => { 
      if (event.lengthComputable) { 
       this.uploadedFiles[index].updateProgress(
        Math.round((event.loaded * 100)/event.total) 
       ); 
      } 
     }; 
     //endregion 

     //region reader.onloadend 
     reader.onloadend = (event: ProgressEvent) => { 
      const target: FileReader = <FileReader>event.target; 
      const content = target.result.split(',')[1]; 

      this.uploadedFiles[index].contentLoaded(content); 
     }; 
     //endregion 

     reader.readAsDataURL(file); 
    }); 
} 

Metoda ta działa przy użytkowników kliknie przycisk Zapisz

public upload(uploadedFiles: UploadedFile[]) : Observable<null> { 
    const body: object = { 
     files: uploadedFiles.map((uploadedFile) => { 
      return { 
       filename: uploadedFile.name, 
       // SLOWDOWN HAPPENS HERE 
       content: uploadedFile.content 
      }; 
     }) 
    }; 

    return this.http.post('file', body) 
} 
+0

Pytasz o problem z kodem, ale nie publikujesz żadnej jego linii. –

+0

@JB Nizet Dodałem odpowiedni kod – realshadow

+0

Co się stanie, jeśli sam zbudujesz ciąg JSON za pomocą prostego łączenia ciągów (skoro wiesz, że base64 nie zawiera żadnych znaków, które muszą być zakodowane), zamiast pozwolić http to zrobić? –

Odpowiedz

3

Do wysyłania dużych plików na serwerze należy użyć FormData aby móc wysłać go jako wieloczęściowy zamiast pojedynczego dużego pliku.

Coś jak:

// import {Http, RequestOptions} from '@angular/http'; 
 
uploadFileToUrl(files, uploadUrl): Promise<any> { 
 
    // Note that setting a content-type header 
 
    // for mutlipart forms breaks some built in 
 
    // request parsers like multer in express. 
 
    const options = new RequestOptions(); 
 
    const formData = new FormData(); 
 

 
    // Append files to the virtual form. 
 
    for (const file of files) { 
 
    formData.append(file.name, file) 
 
    } 
 
    // Send it. 
 
    return this.http.post(uploadUrl, formData, options); 
 
    
 
}

Również nie zapomnij ustawić nagłówek 'Content-Type': undefined, mam porysowane głowę nad tym godzinami.

+0

To nie rozwiązuje mojego problemu, ponieważ nie mogę zmienić interfejsu API. Mam świadomość, że to wydaje się być jedynym rozwiązaniem, więc szukam odpowiedzi, dlaczego zajmuje to tyle czasu, aby obsłużyć żądanie. tak czy inaczej – realshadow

+0

W tym przypadku pamiętaj, że jedyną rzeczą, która przychodzi Ci do głowy, to użycie kompresji http/deflate @realshadow – Yaser