Node + Angular: скачать файл с HTTP-запросом - PullRequest
0 голосов
/ 20 мая 2019

Я пробовал 400 комбинаций синтаксисов и заголовков, я не могу понять, как сделать HTTP-вызов из Angular, чтобы получить файл с моего сервера NodeJS.

Найден в Stackoverflow и пробовал, но безрезультатно:

Скачать файл с http пост-запроса - Angular 6

Как скачать файл с HttpClient

Загрузить файл с сервера NodeJS с помощью Express

Как загрузить файл с Angular2

Это не может быть простой тег <a download> или общедоступная папка express.static(), потому что доступ к файлу ограничен, и мне нужно передать токен JWT (в Node у меня есть промежуточное ПО для экспресс-аутентификации, которое отклонит запрос, если токен не указан в заголовках или если он недействителен).

Файл представляет собой GZIP: ./dumps/dump.gz и весит 812 Кб.

Мне удается загрузить файл, но что бы я ни пытался, он весит 1,4 МБ или 94 байта (неправильный размер) и не может быть открыт (7zip can't open file downloads/dump.gz as archive).

Что я пробовал Угловая сторона (несколько попыток):

import { saveAs } from 'file-saver';

let headers = new Headers({
    "Authorization": "Bearer " + user.jwt, // I need this in the headers

    "Content-Type" : "application/octet-stream", // Tried with and without, "application/gzip", "application/json", no difference

    "responseType": "blob" as "json", // Tried with and without, "text", "json", no difference

    "Access-Control-Expose-Headers" : "Content-Disposition" // Tried with and without, no difference
})

this.http
    .get("/download/dump", { headers })
    .toPromise()
    .then(res => {

        const blob = new Blob([res["_body"]] , { type: "application/octet-stream;"} );  // Error : body is not a blob or an array buffer
        // const blob = new Blob([res["_body"]]); // Same result
        // const blob = new Blob([res.blob()]); // Error : body is not a blob or an array buffer

        saveAs(blob, "dump.gz"); // Saves a big corrupted file

        // window.URL.createObjectURL(new Blob(blob, {type: 'blob'})); Saves a 94 byte corrupted file. Tried {type: 'gzip'}, same thing
    })
    .catch(err => console.error("download error = ", err))

Что я пробовал Сторона узла (несколько попыток):

EDIT

Узел был невиновным, так как я мог получить файл напрямую из Chrome после отключения аутентификации. Итак, бэкэнд работает и проблема в Angular.

app.get( "/download/dump", authenticate, (req:Request, res:Response) => {
    const file = path.resolve(__dirname, `./dumps/dump.gz`);

    res
        .set({ // Tried with and without headers, doesn't seem to do anything
            "Content-Disposition" : "attachment",  // Tried with and without
            "filename" : "dump.gz", // Tried with and without
            "filename*" : "dump.gz",  // Tried with and without
            "Content-Encoding" : "gzip",  // Tried with and without
            "Content-Type" : "application/gzip"  // Tried with and without, "application/text", "application/json", no difference 
        })
        .sendFile(file); // getting a big corrupted file
        // .download(file); // Same result (big corrupted file)
})

1 Ответ

0 голосов
/ 24 мая 2019

Предполагая, что вы используете новый HttpClient от углового (доступно начиная с углового 4), это должно работать

front

import { saveAs } from 'file-saver';
import {HttpHeaders} from "@angular/common/http";

let headers = new HttpHeaders({
    "Authorization": "Bearer " + user.jwt, // Auth header
    //No other headers needed
});

this.http
    .get("/download/dump", { headers, responseType: "blob" }) //set response Type properly (it is not part of headers)
    .toPromise()
    .then(blob => {
        saveAs(blob, "dump.gz"); 
    })
    .catch(err => console.error("download error = ", err))

бэкэнд

app.get( "/download/dump", authenticate, (req:Request, res:Response) => {
    const file = path.resolve(__dirname, `./dumps/dump.gz`);
    //No need for special headers
    res.download(file); 
})
...