简体   繁体   English

这是在docker容器内的node.js以及云问题上运行的通用expressjs

[英]This is a general expressjs running on node.js inside a docker container and on the cloud question

I have built two docker images. 我已经建立了两个docker镜像。 One with nginx that serves my angular web app and another with node.js that serves a basic express app. 一个使用nginx服务于我的角度式Web应用程序,另一个使用node.js服务于基本的Express应用程序。 I have tried to access the express app from my browser in two different tabs at the same time. 我试图同时从两个不同的选项卡中的浏览器访问express应用。

In one tab the angular dev server (ng serve) serves up the web page. 在一个标签中,Angular开发服务器(ng服务)为网页提供服务。 In the other tab the docker nginx container serves up the web page. 在另一个标签中,docker nginx容器提供了网页。

While accessing the node.js express app at the same time from both tabs the data starts to mix and mingle and the results returned to both tabs are a mix mash of the two requests (one from each browser tab)... 从两个选项卡同时访问node.js express应用程序时,数据开始混合并混合,返回到两个选项卡的结果是两个请求的混合混搭(每个浏览器选项卡一个)...

I'll try and make this more simple by showing my express app code here...but to answer this question you may not even need to know what the code is at all...so maybe check the question as stated below the code first. 我将通过在此处显示我的快速应用程序代码来尝试使此过程更简单...但是要回答此问题,您甚至可能根本不需要知道代码是什么...因此,请按照代码下方的说明检查问题第一。

'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}`);

The angular app makes a simple request to the express app and waits for the reply...which it properly receives...but when I try to make two requests at the exact same time data starts to get mixed together and results are given back to each browser tab from different accounts... angular应用程序向express应用程序发出一个简单的请求,然后等待回复...它正确接收了...但是当我尝试在完全相同的时间发出两个请求时,数据开始混合在一起并返回结果从不同帐户访问每个浏览器标签...

...and the question is... When running containers in the cloud is this kind of thing an issue? ...问题是...在云中运行容器时,这是问题吗? Does one need to spin up a new container for each client that wants to actively connect to the express service so that their data doesn't get mixed? 是否需要为每个要主动连接到快递服务的客户端增加一个新的容器,以使它们的数据不会混淆?

...or is this an issue I am seeing because the express app is being accessed from locally inside my machine? ...或者这是我看到的一个问题,因为正在从本地计算机内部访问express应用? If two machines with two different ip address tried to access this express server at the same time would this sort of data mixing still be an issue or would each get back it's own set of results? 如果两台具有两个不同IP地址的机器试图同时访问该Express服务器,那么这种数据混合仍然会成为问题,还是会各自返回自己的结果集?

Is this why people use CaaS instead of IaaS solutions? 这就是为什么人们使用CaaS而不是IaaS解决方案的原因吗?

FYI: this is demo code and the data will not be actually going back to the consumer directly...plans are to have it placed into a database and then re-extracted from the database to download all of the metadata headers for each email. 仅供参考:这是演示代码,数据实际上不会直接返回给消费者...计划将其放入数据库中,然后从数据库中重新提取以下载每封电子邮件的所有元数据标头。

-Thank you for your time -感谢您的时间

I can only clear up a small part of this question: 我只能解决这个问题的一小部分:

When running containers in the cloud is this kind of thing an issue? 当在云中运行容器时,这是一个问题吗?

No. Docker is not causing any of the quirky behaviour that you are describing. 不会。Docker不会引起您所描述的任何古怪行为。

Does one need to spin up a new container for each client? 是否需要为每个客户启动一个新的容器?

A docker container generally can serve as much users as the application inside of it can. 一个Docker容器通常可以为其内部的应用程序提供尽可能多的用户服务。 So as long as your application can handle a lot of users (and it should), you don't have to start the same application in multiple containers. 因此,只要您的应用程序可以处理很多用户(并且应该可以),您就不必在多个容器中启动同一应用程序。 That said, when you expect a very large number of customers, there exist docker tools like Docker Compose , Docker Swarm and a lot of alternatives that will enable you to scale up later. 就是说,当您期望有大量客户时,就会有诸如Docker ComposeDocker Swarm之类的Docker工具以及许多其他替代方法,这些使您以后可以进行扩展。 For now, you don't need to worry about this at all. 现在,您完全不必担心这一点。

I think I may have found out the issue with my code...and this is actually very important if you are using the node.js googleapis client library... 我想我可能已经发现了我的代码存在的问题...如果您使用的是node.js googleapis客户端库,这实际上非常重要...

It is entirely necessary to create a new oauth2Client for each request that comes in 完全有必要为每个传入的请求创建一个新的oauth2Client。

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

Problem: When this oauth2Client is shared it is shared by each and every person that connects at the same time...So it is necessary to create a new one each and every time a user connects to my /threads endpoint so that they do not share the same memory space (ie access_token etc.) while the processing is done. 问题:共享此oauth2Client时,每个同时连接的每个人都共享它...因此,每次用户连接到我的/ threads端点时,都需要创建一个新的,这样他们就不会处理完成后,共享相同的内存空间(即access_token等)。

Setting the client secret etc. and creating the oauth2Client just once at the top and then simply resetting the token for each request leads to the conflicts mentioned above. 设置客户端密码等并仅在顶部创建一次oauth2Client,然后简单地为每个请求重置令牌会导致上述冲突。

Solution: For now simply moving the creation of this oauth2Client into each and every request that comes in makes this work properly. 解决方案:现在,只需简单地将此oauth2Client的创建移动到每个传入的请求中,即可使其正常工作。

Each client that connects to the service NEEDS to have their own newly created oauth2Client instance or these types of conflicts will occur... 连接到服务NEEDS的每个客户端都有自己的新创建的oauth2Client实例,否则将发生这些类型的冲突...

...it's kind of a no brainer but I still find it odd that there is nothing about this in the docs? ...这有点儿费劲,但我仍然觉得奇怪的是,文档中对此一无所知? and their own examples ( https://github.com/googleapis/google-api-nodejs-client ) seem to show only one instance being created for the whole of their app...but those examples are snippets so... 和他们自己的示例( https://github.com/googleapis/google-api-nodejs-client )似乎只显示了为其整个应用创建的一个实例...但是这些示例都是片段...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM