Как убедиться, что файл загружен, а затем вернуть ответ на клиентскую сторону?

Мне нужно загрузить файл json с помощью nodejs и отреагировать. Итак, когда пользователь нажимает кнопку загрузки, запрос отправляется на nodejs, затем я делаю http-запрос, передавая пользователя, пароль и URL-адрес для загрузки файла json на сервер, а затем загружаю этот файл на стороне клиента.

Загрузка файла на стороне сервера занимает почти 5 минут, проблема в том, что я получаю сетевую ошибку до завершения загрузки файла:

GET http://127.0.0.1:4000/downloadFile net::ERR_EMPTY_RESPONSE
Error: Network Error
    at createError (createError.js:17)
    at XMLHttpRequest.handleError (xhr.js:80)

Когда нажимается кнопка загрузки, эта функция на стороне реакции вызывается:

downloadFile() {
    this.setState({ buttonDownloadText: 'Wait ...' })
    axios.get(process.env.REACT_APP_HOST + '/downloadFile')
      .then(resp => {            
        window.open(process.env.REACT_APP_HOST + '/download?namefile=' + resp.data.fileName, '_self')           

        this.setState({ buttonDownloadText: 'Start download' })    

      })
      .catch((error) => {
        console.info(error) //here is where the Network Error is returned
        this.setState({ buttonDownloadText: 'Error. Try again' })
      })
  }

Сторона сервера:

  const http = require('http');
  const fs = require('fs');

    app.get('/downloadFile', function (req, res, next) {
        try {
            const headers = new Headers();
            const URL = env.URL_API + '/api/downloadFile'
            const DOWNLOADURL = env.URL_API + '/api/download'
            headers.set('Authorization', 'Basic ' + base64.encode(username + ":" + password));

            fetch(URL, {
                method: 'GET',
                headers: headers,
            })
                .then(r => r.json())
                .then(data => 
                    fetch(DOWNLOADURL + '/' + data.fileName, {
                        method: 'GET',
                        headers: headers,
                    }).then(result => {   
                                const url = 'http://user:pass@url' + data.fileName
                                const arq = __dirname + '/download/' + data.fileName

                                var file = fs.createWriteStream(arq);
                                http.get(url, function (response) {
                                    response.pipe(file);
                                    file.on('finish', () => file.close(() => res.status(200).send({ file: data.fileName });)) //I have to return the file name to react function
                                });


                            }).catch(error => {
                                logger.error(`${error}`);
                            })
                    })
                        .catch(error => {
                            logger.error(`${error.status || 500} - ${error} - ${req.originalUrl} - ${req.method} - ${req.ip}`);
                            res.sendStatus(500)
                        })
               ....
    });

downloadFile функция должна возвращать имя файла, поэтому я вызываю маршрут загрузки, чтобы сделать загрузку на стороне клиента

app.get('/download', function (req, res) {
    try {
        const file = __dirname + '/download/' + req.query.namefile;
        res.download(file);
    } catch (error) {
        logger.error(`${error.status || 500} - ${error} - ${req.originalUrl} - ${req.method} - ${req.ip}`);
    }
});

Итак, я хочу сказать, почему мой маршрут downloadFile не ждет окончания загрузки файла, чтобы вернуть его res.status(200).send({ file: data.fileName })?

К сожалению, если получение ответа от сервера занимает слишком много времени, клиент обычно возвращает ошибку тайм-аута. Я предлагаю использовать другой подход, например загрузить файл в облачную корзину (например, AWS S3 или Firebase) и вернуть ссылку клиенту.

Michele 03.07.2019 14:31

@Michele, нельзя ли избежать ошибки тайм-аута со стороны клиента?

mr.abdo 03.07.2019 14:36

Насколько мне известно, невозможно заставить браузер ждать ответа. Кроме того, вы не можете полагаться на браузеры. Кроме того, хорошей практикой является предоставление статического URL-адреса клиенту, поскольку он может приостановить / возобновить процесс загрузки на ходу.

Michele 03.07.2019 14:39

Я понял. Тку так много!

mr.abdo 03.07.2019 14:42
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
4
544
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Поскольку браузеры нельзя заставить ждать долгого ответа от сервера, я предлагаю другой подход: загрузить файл в облако (например, AWS или Firebase) и вернуть ссылку клиенту.

При использовании Firebase (или другой базы данных в реальном времени) сервер может установить флаг в базе данных, когда загрузка файла завершена. Поэтому клиент получает уведомление асинхронно, когда файл доступен для загрузки.

Другие вопросы по теме