Реальная история отладки Chrome расширения с Google Apps Script. Узнайте, как clasp спас от копирования URL и как избежать ловушки ANYONE vs ANYONE_ANONYMOUS.
Представьте: вы пишете Chrome расширение для LinkedIn, подключаете к нему Google Таблицу через Apps Script, всё работает. Потом вы меняете одну строку кода, перезаливаете — и получаете сухую 401 ошибку. Никаких пояснений, только чувство, что Google вас обманул. Знакомо? Сегодня я расскажу, как я потратил несколько часов на отладку этой ошибки и как нашёл спасение в CLI-инструменте clasp.
Я сделал Chrome расширение ProfileKit. Оно парсит страницы профилей LinkedIn: имя, должность, компанию. Всё просто, для личного использования. Потом я захотел кнопку «Сохранить профиль»: нажал — и человек попадает в Google Таблицу, привязанный к строке своей компании. Несколько профилей на компанию, без дубликатов, автосинхронизация.
Но для этого нужен бэкенд. Поднимать сервер для пет-проекта, который используется 20 раз в день, не хотелось. Тогда Shrijith подсказал идею: превратить Google Apps Script Web App в бесплатный API, а Google Таблицу — в базу данных.
Вот как выглядит вызов из расширения:
// background.js
fetch(SHEET_SYNC_URL, {
method: "POST",
body: JSON.stringify(message.payload),
redirect: "follow"
})
.then(res => res.text())
.then(text => sendResponse({ok: true, data: JSON.parse(text)}))
.catch(err => sendResponse({ok: false, error: err.message}));
А на стороне Apps Script функция doPost сопоставляет лид с компанией и добавляет строку. Бесплатный хостинг, бесплатная аутентификация (теоретически), бесплатная база данных. Что могло пойти не так?
Сначала мелкий баг: я сопоставлял лиды с компаниями по названию. «EmpInfo» vs «EmpInfo, Inc.» — неоднозначно, хрупко. Я исправил это, используя URL компании с LinkedIn как ключ. Всё стало надёжно.
Потом я перезалил обновлённый код Apps Script — и всё сломалось. Каждый запрос возвращал 401. Не «у вас баг», не «колонка не найдена», а плоский, безликий 401, который приходил от инфраструктуры Google до того, как мой код вообще запускался.
Я проверил настройки развёртывания. Четыре раза. Там крупно написано: «Доступ: Все» (Anyone). Я смотрел на это слово, как будто оно мне должно.
Но оказалось, «Все» и «Все» — не одно и то же. В манифесте, который управляет развёртыванием, стояло:
"webapp": {
"executeAs": "USER_DEPLOYING",
"access": "ANYONE"
}
В API Google ANYONE означает «все, кто вошёл в аккаунт Google». Не анонимные пользователи, не curl, не мой fetch() из расширения (у которого нет кук Google). Настоящее значение «публичный доступ, без логина» — это ANYONE_ANONYMOUS.
Интерфейс говорит «Все», а API различает два вида «всех». И только один из них — действительно все. Это как объявление «можно с животными», а потом выясняется, что можно только с одной золотой рыбкой под присмотром.
Я исправил и проверил простым запросом:
curl -s "$DEPLOY_URL" -w "\n%{http_code}\n"
# {"ok":false,"error":"Use POST"}
# 200
Настоящий ответ. От незнакомца. Анонимно. Как и обещано, в конце концов.
Вот что действительно стоит описать. Каждый раз, когда я что-то правил в файле Apps Script, процесс выкладки был таким: открыть веб-редактор, вставить код вручную, нажать «Развернуть», «Управление развёртываниями», создать новую версию, скопировать новый URL /exec, вставить его в background.js расширения, обновить версию манифеста, перезагрузить расширение, обновить все открытые вкладки LinkedIn.
Для одной изменённой строки. Я делал это достаточно раз, чтобы спросить вслух: «Неужели нет пакета для этого?»
Оказалось, есть. Называется clasp — официальный CLI для Apps Script от Google. Он позволяет пушить код, создавать версии и управлять развёртываниями прямо из терминала.
npm install -g @google/clasp
clasp login # одноразовая OAuth в браузере
clasp clone <scriptId>
Часть, которая решила проблему с URL:
clasp deploy -i <existingDeploymentId> -V <newVersionNumber>
Эта команда обновляет существующее развёртывание, указывая на новую версию. Тот же ID развёртывания, тот же URL /exec, навсегда. Больше никакого копирования нового URL каждый раз.
Я обернул push, создание версии и переразвёртывание в один скрипт и Make-цель:
make apps-script-deploy MSG="fix lead matching"
Вот и всё. Весь процесс релиза.
До: открыть редактор → вставить код → развернуть → скопировать URL → вставить в расширение → обновить версию → перезагрузить.
После: make apps-script-deploy MSG="..." → готово.
Chrome расширение, общающееся с Google Таблицей через Apps Script Web App — это не серьёзная архитектура. Хочу это подчеркнуть.
Но это полностью бесплатно, не требует сервера, базы данных, системы аутентификации. Я потратил вечер, чтобы всё настроить. Для личного инструмента, который один человек использует пару десятков раз в день — это фантастический компромисс.
Просто знайте об одной ловушке в манифесте и установите clasp заранее, а не после трёх часов 401 ошибок.
Прямо сейчас сделайте две вещи:
access: "ANYONE_ANONYMOUS", а не ANYONE.clasp deploy -i <id> -V <version>.Это сэкономит вам часы отладки и кучу нервов. А если хотите глубже изучить clasp — вот репозиторий на GitHub и руководство по Web Apps.
Хочешь закрепить знания на практике?
Решай задачи на Algolit — интерактивная платформа для обучения
Начать бесплатно →