Node.js: ожидание запроса

Я новичок в Node.js, работаю с примером проекта стороннего поставщика и пытаюсь использовать Azure Key Vault для хранения значений конфигурации.

У меня возникли проблемы с получением процесса wait перед выполнением остальных. Постараюсь подробно описать, насколько знаю.

пример проекта имеет файл с именем agent.js, который является стартовой страницей/файлом. На строка 16 (agent_config = require('./config/config.js')[process.env.LP_ACCOUNT][process.env.LP_USER]) вызывает файл конфигурации со значениями. Я пытаюсь установить эти значения с помощью Key Vault. Я пробовал множество комбинаций функций вызова и даже реализацию async / await, но значение agent_config всегда содержит объект [Promise], а не данные, возвращаемые Key Vault.

Если я прав, это связано с тем, что само Key Vault также использует async / await, и файл конфигурации возвращается до того, как возвращаются значения Key Vault.

Как можно добавить/внедрить Key Vault в такой ситуации?

Вот что я пробовал:

Сначала обновлен агент.js до

let agent_config = {};
try {
  agent_config = require('./config/config.js')['123']['accountName'];
} catch (ex) {
  log.warn(`[agent.js] Error loading config: ${ex}`)
}

console.info(agent_config);

Тест 1

./config/config.js

const KeyVault = require('azure-keyvault');
const msRestAzure = require('ms-rest-azure');
const KEY_VAULT_URI = 'https://' + '{my vault}' + '.vault.azure.net/' || process.env['KEY_VAULT_URI'];

function getValue(secretName, secretVersion) {
  msRestAzure.loginWithAppServiceMSI({ resource: 'https://vault.azure.net' }).then((credentials) => {
    const client = new KeyVault.KeyVaultClient(credentials);
    client.getSecret(KEY_VAULT_URI, secretName, secretVersion).then(
      function (response) {
        return response.Value;
      });
  });
}

module.exports = {
    '123': {
        'accountName': {
            accountId: getValue('mySecretName', '')
         }
     }
};

Результаты

{ accountsId: undefined }

Тест 2

Сделал получить значение функцией async и обернул ее вокруг другой функции (попробовал без обертки, тоже не сработало)

./config/config.js

const KeyVault = require('azure-keyvault');
const msRestAzure = require('ms-rest-azure');
const KEY_VAULT_URI = 'https://' + '{my vault}' + '.vault.azure.net/' || process.env['KEY_VAULT_URI'];

async function getValue(secretName, secretVersion) {
  msRestAzure.loginWithAppServiceMSI({ resource: 'https://vault.azure.net' }).then((credentials) => {
    const client = new KeyVault.KeyVaultClient(credentials);
    client.getSecret(KEY_VAULT_URI, secretName, secretVersion).then(
      function (response) {
        return response.Value;
      });
  });
}

async function config() {
    module.exports = {
        '123': {
            'accountName': {
                accountId: await getValue('mySecretName', '')
             }
         }
    };
}

config();

Результаты

{}

Тест 3

Сделал получить значение функцией async и обернул ее вокруг другой функции (попробовал без обертки, тоже не сработало)

./config/config.js

const KeyVault = require('azure-keyvault');
const msRestAzure = require('ms-rest-azure');
const KEY_VAULT_URI = 'https://' + '{my vault}' + '.vault.azure.net/' || process.env['KEY_VAULT_URI'];

async function getValue(secretName, secretVersion) {
  return msRestAzure.loginWithAppServiceMSI({ resource: 'https://vault.azure.net' })
    .then((credentials) => {
      const client = new KeyVault.KeyVaultClient(credentials);
      return client.getSecret(KEY_VAULT_URI, secretName, secretVersion).then(
        function (response) {
          return response.Value;
        });
    });
}

module.exports = {
    '123': {
        'accountName': {
            accountId: getValue('mySecretName', '')
        }
    }
};

config();

Результаты

{ accountId: { <pending> } }

Другой

Я пробовал много других способов, таких как module.exports = async (value) =< {...} (безуспешно нашел через другие вопросы/решения.

Я начинаю думать, что мне нужно немного «подождать» agent.js, но я не нашел хорошей информации об этом.

Любая помощь будет здорово!

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
2
0
407
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

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

(и без возврата обещания ждать нечего)

async function getValue(secretName, secretVersion) {
  return msRestAzure.loginWithAppServiceMSI({ resource: 'https://vault.azure.net' })
    .then((credentials) => {
      const client = new KeyVault.KeyVaultClient(credentials);
      return client.getSecret(KEY_VAULT_URI, secretName, secretVersion).then(
        function (response) {
          return response.Value;
        });
    });
}

Вы также можете уйти с менее явным возвратом, используя стрелочные функции.

const getValue = async (secretName, secretVersion) => 
  msRestAzure.loginWithAppServiceMSI({ resource: 'https://vault.azure.net' })
    .then(credentials => {
      const client = new KeyVault.KeyVaultClient(credentials);
      return client.getSecret(KEY_VAULT_URI, secretName, secretVersion)
        .then(response => response.Value);
    });

Представление чтения Azure Key Vault, которое является асинхронным, означает, что вся ваша конфигурация читается асинхронно. Вы ничего не можете сделать, чтобы обойти это. Это будет означать, что код, который использует конфигурацию, должен будет обрабатывать ее соответствующим образом. Вы начинаете с экспорта асинхронной функции, которая вернет конфигурацию.

async function getConfig() {
  return {
    '123': {
      'accountName': {
        accountId: await getValue('mySecretName', '')
      }
    }
  };
}

module.exports = getConfig;

В коде вашего агента вы вызываете эту функцию. Это будет означать, что ваш код агента также должен быть обернут в функцию, поэтому, возможно, что-то вроде этого.

const Bot = require('./bot/bot.js');
const getConfig = require('./config/config.js');

getConfig().then(agentConfig => {
    const agent = new Bot(agentConfig);

    agent.on(Bot.const.CONNECTED, data => {
        log.info(`[agent.js] CONNECTED ${JSON.stringify(data)}`);
    });
});

Спасибо. Однако это приводит к тому же самому. { accountId: Promise { <pending> } }

RoLYroLLs 05.03.2019 15:18

добавил это как тест 3

RoLYroLLs 05.03.2019 15:21

Вы делаете это неправильно в тесте 3. Вы должны подождать getValue. Но это приведет к тому, что ваш конфиг должен быть обернут внутри асинхронной функции, что-то вроде теста 1. Кстати, вы делаете это неправильно в тесте 1: не устанавливайте module.exports там, вместо этого возвращайте объект, который будет назначен module.exports.

Pritilender 05.03.2019 16:01

добавил пример использования в мой ответ

lecstor 05.03.2019 23:09

@lecstor спасибо за использование примера. Когда я использую его как есть, я получаю следующую ошибку "Unexpected identifier". Кажется, это function async getConfig() {...} Когда я переключаю порядок function и async, я не получаю ошибку, однако я получаю результат { accountId: undefined }. Я что-то пропустил?

RoLYroLLs 06.03.2019 20:13

@RoLYroLLs, может быть, у вас нет секрета с таким именем в вашем хранилище Azure?

Pritilender 06.03.2019 22:14

@RoLYroLLs, вы можете проверить, сработает ли это? gist.github.com/Притилендер/7ae1d68331b5f76c818e601760bd2db2

Pritilender 06.03.2019 22:18

упс, спасибо, исправлена ​​опечатка. Не уверен насчет неопределенного accountId сейчас. Я бы добавил ведение журнала в getValue, чтобы проверить, что credentials и response соответствуют ожиданиям.

lecstor 06.03.2019 22:51

@lecstor Скрипт от Pritilender действительно работает. Не уверен, почему.

RoLYroLLs 06.03.2019 22:59
response => response.Value похоже, что «значение» должно быть в нижнем регистре
lecstor 06.03.2019 23:03

@lecstor твой скрипт тоже работает!! Я нашел еще одну опечатку, которая сбила меня с толку. Ваша функция getValue имеет дополнительный } в конце. Я думал, вы забыли вводную в самом начале. Вместо этого я удалил последний }, и это сработало. Я не могу отредактировать ваше сообщение, так как изменился только 1 символ.

RoLYroLLs 06.03.2019 23:22

@RoLYroLLs, мой сценарий просто асинхронно / ожидает перезаписи лекстора. Несмотря на то, что вам удалось заставить его код работать, я бы посоветовал не использовать этот стиль кодирования, поскольку он делает код немного нечитаемым. Без обид, лекстор, просто если вы уже заявляете, что функция асинхронна, то используйте в ней await вместо вложенных обратных вызовов обещаний.

Pritilender 08.03.2019 10:13

@Pritilender, все хорошо, я согласен с этим, я просто пытался сохранить код как можно ближе к исходному сообщению.

lecstor 08.03.2019 11:00

Пакет azure-keyvault устарел в пользу новых пакетов для отдельной работы с ключами, секретами и сертификатами Keyvault. В вашем сценарии вы можете использовать новый пакет @azure/keyvault-секреты для взаимодействия с Key Vault и новый пакет @лазурь/идентификация для создания учетных данных.

const { SecretClient } = require("@azure/keyvault-secrets");
const { DefaultAzureCredential } = require("@azure/identity");

async function getValue(secretName, secretVersion) {
  const credential = new DefaultAzureCredential();
  const client = new SecretClient(KEY_VAULT_URI, credential);
  const secret = await client.getSecret(secretName);
  return secret.value;
}

DefaultAzureCredential предполагает, что вы установили следующие переменные env

  • AZURE_TENANT_ID: идентификатор клиента в Azure Active Directory.
  • AZURE_CLIENT_ID: идентификатор приложения (клиента), зарегистрированный в клиенте AAD.
  • AZURE_CLIENT_SECRET: секрет клиента для зарегистрированного приложения.

Чтобы попробовать другие учетные данные, см. ридми для @azure/identity Если вы переходите со старого пакета azure-keyvault, ознакомьтесь с руководство по миграции, чтобы понять основные изменения.

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