При работе с UrlFetchApp
в Google Apps Script разработчики сталкиваются с фундаментальной проблемой: исходящие запросы отправляются с динамических IP-адресов. Это становится непреодолимым препятствием, когда внешний API требует, чтобы запросы приходили только с заранее известных IP-адресов, добавленных в “белый список”.
Решением является создание прокси-сервера в Yandex.Cloud. Это руководство предлагает два проверенных сценария, а также лучшие практики для безопасного и надежного развертывания.
Архитектура: Google Apps Script → Yandex API Gateway → Yandex Cloud Function → Интернет
package.json
:
{
"name": "proxy-function",
"version": "1.0.0",
"main": "index.js",
"dependencies": {
"axios": "^1.7.2"
}
}
index.js
:
const axios = require('axios');
module.exports.handler = async (event) => {
const body = JSON.parse(event.body);
const { targetUrl, method, headers, body: requestBody } = body;
if (!targetUrl) {
return { statusCode: 400, body: JSON.stringify({ error: 'Параметр "targetUrl" обязателен.' }) };
}
const headersToForward = { ...headers };
delete headersToForward.host;
try {
const response = await axios({
method: method || 'GET',
url: targetUrl,
headers: headersToForward,
data: requestBody || {},
timeout: 10000, // Таймаут 10 сек. Увеличьте, если целевой API отвечает дольше.
validateStatus: () => true, // Позволяет проксировать ответы с ошибками (4xx/5xx).
});
return {
statusCode: response.status,
headers: response.headers,
body: JSON.stringify(response.data),
};
} catch (error) {
// Ошибка, когда ответ от сервера не получен (сеть, DNS, таймаут).
console.error('Ошибка при выполнении прокси-запроса:', error.message);
return {
statusCode: 502, // Bad Gateway
body: JSON.stringify({ error: 'Ошибка прокси-шлюза', details: error.message }),
};
}
};
Настройка прав: Перед созданием шлюза убедитесь, что у вас есть сервисный аккаунт с ролью
serverless.functions.invoker
для вашей функции. Это делается вIAM
и на вкладке “Права доступа” вашей функции.
openapi: 3.0.0
info:
title: Simple Proxy API
version: 1.0.0
paths:
/proxy:
post:
summary: Proxies a request
x-yc-apigateway-integration:
type: cloud_functions
function_id: YOUR_FUNCTION_ID
service_account_id: YOUR_SERVICE_ACCOUNT_ID_WITH_INVOKER_ROLE
# (остальная спецификация...)
function callServiceViaYandexProxy() {
const proxyUrl = 'https://YOUR-API-GATEWAY-URL.apigw.yandexcloud.net/proxy';
const proxyPayload = {
targetUrl: 'https://api.example.com/data',
method: 'GET',
headers: { 'Authorization': 'Bearer YOUR_SECRET_TOKEN' }
};
const options = {
method: 'post',
contentType: 'application/json',
payload: JSON.stringify(proxyPayload),
muteHttpExceptions: true
};
const response = UrlFetchApp.fetch(proxyUrl, options);
Logger.log('Статус: %s, Ответ: %s', response.getResponseCode(), response.getContentText());
}
Архитектура: Apps Script → API Gateway → Cloud Function (в VPC) → NAT-инстанс (Статический IP) → Интернет
Выполните все те же шаги, что и в Сценарии А, со следующими изменениями на уровне инфраструктуры:
0.0.0.0/0
) через внутренний IP NAT-инстанса, и привяжите ее к подсети.Примечание по безопасности: Убедитесь, что для вашей сети настроены группы безопасности (Security Groups), разрешающие исходящий трафик по портам 80 (HTTP) и 443 (HTTPS) от NAT-инстанса.
Прежде чем использовать решение в реальных проектах, рекомендуется выполнить следующие шаги.
Чтобы отлаживать функцию без развертывания в облаке, можно протестировать ее логику локально.
index.js
.Создайте рядом файл test.js
:
// test.js
const { handler } = require('./index');
// Эмулируем объект event, который приходит от API Gateway
const mockEvent = {
httpMethod: 'POST',
body: JSON.stringify({
targetUrl: 'https://httpbin.org/get', // Используем тестовый сервис
method: 'GET',
headers: { 'Accept': 'application/json' }
})
};
// Вызываем хендлер и выводим результат
handler(mockEvent).then(response => {
console.log('Результат выполнения:', response);
});
node test.js
. Это поможет быстро найти ошибки в логике, не дожидаясь развертывания.Публичный URL шлюза — это открытая дверь. Чтобы ее защитить, используйте API-ключи.
Обновите спецификацию, добавив требование безопасности:
# ... (начало спецификации)
paths:
/proxy:
post:
security: # <-- Добавьте этот блок
- ApiKeyAuth: []
# ... (остальные параметры)
# ... (конец спецификации)
components:
securitySchemes: # <-- И этот блок
ApiKeyAuth:
type: apiKey
in: header
name: X-Yc-Apigateway-Api-Key
Обновите код Apps Script, чтобы передавать ключ в заголове:
const options = {
method: 'post',
contentType: 'application/json',
headers: { // <-- Добавьте этот блок
'X-Yc-Apigateway-Api-Key': 'ВАШ_API_КЛЮЧ'
},
payload: JSON.stringify(proxyPayload),
muteHttpExceptions: true
};
Регулярно проверяйте журналы выполнения в Yandex.Cloud:
Следуя этим рекомендациям, вы построите не просто рабочее, а по-настоящему надежное, безопасное и удобное в поддержке решение.