Перенаправление с React на экспресс-маршрут с моего API-сервера в том же домене - PullRequest
0 голосов
/ 17 октября 2018

У меня есть и приложение React APP, и сервер Express API на одном сервере / домене.Nginx обслуживает приложение React APP и прокси-сервер экспресс-доступа в /api.

Конфигурация Nginx https://gist.github.com/dvriv/f4cff6e07fe6f0f241a9f57febd922bb

(сейчас я использую IP-адрес вместо домена)

Из приложения React, когда пользователь что-то делает, я хочу, чтобы он загрузил файл.Я использовал экспресс-маршрут на своем сервере API, который обслуживает файл.Это прекрасно работает, когда пользователь вводит URL.

Это мой экспресс-маршрут:

donwloadFile.route('/')
  .get((req, res) => {
    const file = '/tmp/PASOP180901.txt';
    res.download(file);
  });

Это мой перенаправленный ответ:

if (this.state.downloadFile === true) {
  this.setState({ downloadFile: false });
  setTimeout(() => {
    window.location.href = '/api/downloadFile';
  }, 100);
}

Адрес меняется, нозагрузка не начинается.Если я нажму F5, то загрузка начнется просто отлично.Если я использую внешний URL-адрес для размещения моего файла, загрузка тоже начнется нормально.

Спасибо

1 Ответ

0 голосов
/ 17 октября 2018

обо всем по порядку.Не используйте setTimeout, а используйте callback функцию setState для выполнения кода после состояние установлено , гарантирующее его изменение.Вызов функции обратного вызова гарантирует, что состояние будет изменено до выполнения этого кода в обратном вызове.

из официальных документов :

setState () ставит изменения в очередьв состояние компонента и сообщает React, что этот компонент и его дочерние элементы необходимо повторно отобразить в обновленном состоянии.Это основной метод, используемый вами для обновления пользовательского интерфейса в ответ на обработчики событий и ответы сервера.

setState () не всегда сразу обновляет компонент.Это может пакетировать или отложить обновление до позже.Это делает чтение this.state сразу после вызова setState () потенциальной ловушкой.Вместо этого используйте componentDidUpdate или обратный вызов setState (setState (Updater, callback)), любой из которых гарантированно сработает после применения обновления.

setState(stateChange[, callback])

Второй параметр дляsetState () - это дополнительная функция обратного вызова, которая будет выполнена после завершения setState и повторного рендеринга компонента.Обычно мы рекомендуем использовать componentDidUpdate () для такой логики.

Итак, вместо:

if (this.state.downloadFile === true) {
  this.setState({ downloadFile: false });
  setTimeout(() => {
    // execute code, or redirect, or whatever
  }, 100);
}

вы должны сделать:

if (this.state.downloadFile === true) {
  this.setState({ downloadFile: false }, () => {
    // execute code, or redirect, or whatever
  });
}

Теперь, для вашей конкретной проблемы

Установка заголовков на стороне сервера

Вы можете установить заголовок Content-Disposition, чтобы сообщить браузеру о загрузке вложения:

из здесь :

В обычном HTTP-ответе заголовок ответа Content-Disposition является заголовком, указывающим, предполагается ли, что содержимое будет отображаться встроеннымв браузере, то есть как веб-страница или как часть веб-страницы, или как вложение, которое загружается и сохраняется локально.

Установите его так:

('Content-Disposition: attachment; filename="/tmp/PASOP180901.txt"');

Принудительная загрузка с клиента

Существует несколько способов принудительной загрузки с клиента, но я попробовал только один.

Чтобы это работало, у вас должно быть содержимое text в клиенте (ваш экспресс-маршрут может бытьнапример,) и создайте filename для файла, который будет загружен.

let element = document.createElement('a');
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
element.setAttribute('download', filename);
document.body.appendChild(element);
element.click();
document.body.removeChild(element);

В основном вы создаете пустой компонент ссылки, устанавливаете для него атрибут данных с содержимым текста, присоединяетессылку на тело, щелкнув ссылку, а затем удалив ссылку из тела.

Открыть ссылку в новой вкладке

Открытие ссылки в новой вкладке приведет ктакже вызвать загрузку:

window.open('/api/downloadFile');

Перенаправить программно

Посмотрите на этот вопрос в SO

Youможно сделать это:

this.props.history.push("/api/downloadFile")?

Если нет доступа к this.props.history, вы можете import { withRouter } from 'react-router-dom'; и export default withRouter(yourComponent); для доступа к нему.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...