Ожидание http-запроса в AWS Lambda / Pulumi
У меня есть функция AWS Lambda, которая запускает запрос https в Google API. Я хочу, чтобы функция была ожидаемой, чтобы она не заканчивалась сразу, а только после получения ответа от Google API. Да, я знаю, что я плачу за казнь, но это не будет часто называться, так что все в порядке.
Проблема в том, что http-запрос не запускается правильно. Обратный вызов никогда не выполняется.
Я убедился, что async / await работает, как и ожидалось, используя setTimeout в Promise. Так что проблема где-то в https.request.
Также обратите внимание, что я использую Pulumi для развертывания в AWS, поэтому там может быть какая-то скрытая проблема. Я просто не могу понять, где.
Соответствующий код:
AWS Lambda, которая вызывает Google API
import config from '../../config';
import { IUserInfo } from '../../interfaces';
const https = require('https');
function sendHttpsRequest(options: any): Promise<any> {
console.log(`sending request to ${options.host}`);
console.log(`Options are ${JSON.stringify(options)}`);
return new Promise(function (resolve, reject) {
console.log(` request to ${options.host} has been sent A`);
let body = new Array<Buffer>();
const request = https.request(options, function (res: any) {
console.log('statusCode:', res.statusCode);
console.log('headers:', res.headers);
if (res.statusCode != 200) {
reject(res.statusCode);
}
res.on('data', (data: any) => {
console.log(`body length is ${body.length}`);
console.log('data arrived', data);
body.push(data);
console.log('pushed to array');
console.log(data.toString());
});
});
request.on('end', () => {
console.error('Request ended');
// at this point, `body` has the entire request body stored in it as a string
let result = Buffer.concat(body).toString();
resolve(result);
});
request.on('error', async (err: Error) => {
console.error('Errooooorrrr', err.stack);
console.error('Errooooorrrr request failed');
reject(err);
});
request.end();
console.log(` request to ${options.host} has been sent B`);
});
}
/**
* AWS Lambda to create new Google account in TopMonks domain
*/
export default async function googleLambdaImplementation(userInfo: IUserInfo) {
const payload = JSON.stringify({
"primaryEmail": userInfo.topmonksEmail,
"name": {
"givenName": userInfo.firstName,
"familyName": userInfo.lastName
},
"password": config.defaultPassword,
"changePasswordAtNextLogin": true
});
const resultResponse: Response = {
statusCode: 200,
body: 'Default response. This should not come back to users'
}
console.log('Calling google api via post request');
try {
const options = {
host: 'www.googleapis.com',
path: '/admin/directory/v1/users',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': payload.length.toString()
},
form: payload
}
const responseFromGoogle = await sendHttpsRequest(options);
console.log('responseFromGoogle', JSON.stringify(responseFromGoogle));
}
catch (err) {
console.log('Calling google api failed with error', err);
resultResponse.statusCode = 503;
resultResponse.body = `Error creating new Google Account for ${userInfo.topmonksEmail}.`;
return resultResponse;
}
console.log('request to google sent');
return resultResponse;
}
1 ответ
Проблема в том, что http-запрос не запускается правильно. Обратный вызов никогда не выполняется.
Я полагаю, что эта часть проблемы связана с некоторой комбинацией (а) потенциально не отправляющей запрос https и (б) не использования правильной сигнатуры обратного вызова для https.request
, См. Документацию по адресу https://nodejs.org/api/https.html для получения подробной информации по обоим из них.
Используйте пакет node-fetch
Следующий пример работает для меня, используя node-fetch
:
import * as aws from "@pulumi/aws";
import fetch from "node-fetch";
const api = new aws.apigateway.x.API("api", {
routes: [{
method: "GET", path: "/", eventHandler: async (ev) => {
const resp = await fetch("https://www.google.com");
const body = await resp.text();
return {
statusCode: resp.status,
body: body,
}
},
}],
})
export const url = api.url;
Пулуми жалуется, это что-то вроде "Не могу сериализовать нативную функцию" или что-то в этом роде. Проблемная часть состоит в том, что выборка узла полагается на Symbol.iterator
Как отмечено в комментариях, некоторые из условий, которые могут привести к этому, описаны в https://pulumi.io/reference/serializing-functions.html. Тем не менее, я не вижу какой-либо четкой причины, по которой этот код может нарушить любое из этих ограничений. Там могут быть детали того, как это используется вне контекста приведенного выше фрагмента, что приводит к этому.