Это общий expressjs, работающий на node.js внутри контейнера Docker и по облачному вопросу - PullRequest
0 голосов
/ 07 января 2019

Я построил два образа докера. Один с nginx, который обслуживает мое угловое веб-приложение, а другой с node.js, который служит базовым экспресс-приложением. Я пытался получить доступ к приложению Express из моего браузера одновременно на двух разных вкладках.

В одной вкладке сервер угловой разработки (ng serve) обслуживает веб-страницу. На другой вкладке контейнер Docker Nginx обслуживает веб-страницу.

При одновременном доступе к приложению node.js express с обеих вкладок данные начинают смешиваться и смешиваться, а результаты, возвращаемые на обе вкладки, представляют собой смесь двух запросов (по одному на каждой вкладке браузера) ...

Я постараюсь сделать это проще, показав мой экспресс-код приложения здесь ... но чтобы ответить на этот вопрос, вам может даже не понадобиться вообще знать, что это за код ... так что, возможно, проверьте вопрос, как указано сначала под кодом.

'use strict';

/***********************************
GOOGLE GMAIL AND OAUTH SETUP
***********************************/
const fs = require('fs');
const {google} = require('googleapis');
const gmail = google.gmail('v1');

const clientSecretJson = JSON.parse(fs.readFileSync('./client_secret.json'));
const oauth2Client = new google.auth.OAuth2(
  clientSecretJson.web.client_id,
  clientSecretJson.web.client_secret,
  'https://us-central1-labelorganizer.cloudfunctions.net/oauth2callback'
);


/***********************************
EXPRESS WITH CORS SETUP
***********************************/
const PORT = 8000;
const HOST = '0.0.0.0';
const express = require('express');
const cors = require('cors');
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');

const whiteList = [
  'http://localhost:4200',
  'http://localhost:80',
  'http://localhost',
];

const googleApi = express();

googleApi.use(
  cors({
    origin: whiteList
  }),
  cookieParser(),
  bodyParser()
);

function getPageOfThreads(pageToken, userId, labelIds) {

  return new Promise((resolve, reject) => {
    gmail.users.threads.list(
      {
        'auth': oauth2Client,
        'userId': userId,
        'labelIds': labelIds,
        'pageToken': pageToken
      },
      (error, response) => {
        if (error) {
          console.error(error);
          reject(error);
        }
        resolve(response.data);
      }
    )
  });
}

async function getPages(nextPageToken, userId, labelIds, result) {

  while (nextPageToken) {
    let pageOfThreads = await getPageOfThreads(nextPageToken, userId, labelIds);
    console.log(pageOfThreads.nextPageToken);
    pageOfThreads.threads.forEach((thread) => {
      result = result.concat(thread.id);
    })
    nextPageToken = pageOfThreads.nextPageToken;
  }
  return result;
}


googleApi.post('/threads', (req, res) => {
  console.log(req.body);
  let threadIds = [];

  oauth2Client.credentials = req.body.token;
  let getAllThreadIds = new Promise((resolve, reject) => {
    gmail.users.threads.list(
    { 'auth': oauth2Client, 'userId': 'me', 'maxResults': 500 },

      (err, response) => {
        if (err) {
          console.error(err)
          reject(err);
        }
        if (response.data.threads) {
          response.data.threads.forEach((thread) => {
            threadIds = threadIds.concat(thread.id);
          });
        }
        if (response.data.nextPageToken) {
            getPages(response.data.nextPageToken, 'me', ['INBOX'], threadIds).then(result => {
              resolve(result);
            }).catch((err) => {
              console.error(err);
              reject(err);
            });
        } else {
          resolve(threadIds);
        }
      }
    );
  });

  getAllThreadIds
    .then((result) => {
      res.send({ threadIds: result });
    })
    .catch((error) => {
      res.status(500).send({ error: 'Request failed with error: ' + error })
    });

});

googleApi.get('/', (req, res) => res.send('Hello World!'))

googleApi.listen(PORT, HOST);
console.log(`Running on http://${HOST}:${PORT}`);

Приложение angular делает простой запрос к приложению express и ожидает ответа ... который он правильно получает ... но когда я пытаюсь сделать два запроса в одно и то же время, данные начинают смешиваться и результаты возвращаются на каждую вкладку браузера из разных аккаунтов ...

... и вопрос ... При запуске контейнеров в облаке возникает такая проблема? Нужно ли раскручивать новый контейнер для каждого клиента, который хочет активно подключаться к экспресс-службе, чтобы их данные не смешивались?

... или это проблема, с которой я сталкиваюсь, потому что к экспресс-приложению обращаются из моего компьютера? Если две машины с двумя разными IP-адресами будут пытаться получить доступ к этому экспресс-серверу одновременно, будет ли проблема такого рода смешивания данных по-прежнему проблемой или каждая из них получит свой собственный набор результатов?

Вот почему люди используют CaaS вместо решений IaaS?

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

-Спасибо за ваше время

Ответы [ 2 ]

0 голосов
/ 07 января 2019

Я думаю, что, возможно, обнаружил проблему с моим кодом ... и это на самом деле очень важно, если вы используете клиентскую библиотеку googleapis node.js ...

Абсолютно необходимо создать новый клиент oauth2 для каждого входящего запроса

const oauth2Client = new google.auth.OAuth2(
  clientSecretJson.web.client_id,
  clientSecretJson.web.client_secret,
  'https://us-central1-labelorganizer.cloudfunctions.net/oauth2callback'
);

Проблема: Когда этот oauth2Client используется совместно, он используется всеми пользователями, которые подключаются одновременно ... Поэтому необходимо создавать новый каждый раз, когда пользователь подключается к конечной точке my / threads, чтобы они не разделяли то же самое пространство памяти (то есть access_token и т. д.) во время обработки.

Установка секрета клиента и т. Д. И создание oauth2Client только один раз в верхней части, а затем просто сброс токена для каждого запроса приводит к конфликтам, упомянутым выше.

Решение: А пока простое перемещение создания этого oauth2Client в каждый поступающий запрос делает эту работу правильно.

Каждый клиент, который подключается к службе, ДОЛЖЕН иметь свой собственный вновь созданный экземпляр oauth2Client, иначе возникнут конфликты этого типа ...

... это довольно просто, но я все еще нахожу странным, что в документах ничего нет об этом? и их собственные примеры (https://github.com/googleapis/google-api-nodejs-client), кажется, показывают только один экземпляр, создаваемый для всего их приложения ... но эти примеры являются фрагментами, так что ...

0 голосов
/ 07 января 2019

Я могу прояснить только небольшую часть этого вопроса:

При запуске контейнеров в облаке возникает такая проблема?

Нет. Docker не вызывает какого-либо изворотливого поведения, которое вы описываете.

Нужно ли раскручивать новый контейнер для каждого клиента?

Docker-контейнер, как правило, может обслуживать столько же пользователей, сколько приложение внутри него. Поэтому, пока ваше приложение может обрабатывать большое количество пользователей (и оно должно), вам не нужно запускать одно и то же приложение в нескольких контейнерах. Тем не менее, когда вы ожидаете очень большое количество клиентов, существуют такие докерские инструменты, как Docker Compose , Docker Swarm и множество альтернатив, которые позволят вам масштабироваться позже. Пока вам вообще не нужно об этом беспокоиться.

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