Доброго времени суток.
Сегодня мы рассмотрим варианты организации кроссдоменных запросов в юзерскриптах.
В подробности реализации того или иного механизма я вдаваться не буду, но приведу пример кроссбраузерной оболочки для кроссдоменных запросов.
Как известно, в чистом виде в естественной среде браузерного окружения кроссдоменные запросы — штука не тривиальная (благодаря Same origin policy).
Поддержка XMLHttpRequest с CORS есть не во всех браузерах (в опере вообще до сих пор не встречена).
JSONP позволяет только GET-запросы, а проксирование через фреймы заставляет использовать сторонние библиотеки, либо писать жуткие велосипеды.
Перерыв:Если вы дочитали до этого места, и не поняли ни слова, то сделайте перерыв, погуглите неизвестные термины, выпейте чаю. Не унывайте, дальше будут объяснения «на пальцах» и с кодом. Начинающие скриптописатели могут вздохнуть спокойно: вдаваться в подробности мы не будем, но рабочий код и капля теории со всеми ссылками будет в вашем «загашнике».
В чем проблематичность кроссдоменных запросов? Все браузеры ограничивают нашу свободу в угоду безопасности. Посему, запросы из «недоверенных» источников пресекаются на корню. А что делать, если мы источникам доверяем? Правильно, использовать «костыли» (многие из которых являются общепринятой практикой).
В рамках юзерскриптов следует учитывать ограничения, накладываемые окружением, в котором запускаются скрипты (подробности в этой статье) плюс дополнительное важное условие: наличие доступа к серверной части (наличие (или возможность создать) серверного API для реализации конкретного метода запроса)!
Ниже приведена таблица, в которой представлены некоторые «костыли» и их применимость для юзерскриптов.
Для подавляющего большинства скриптов критичным параметром является наличие доступа к серверу. К тому же, чаще всего используются GET-запросы (если скрипт не зловред, не наделён мегаинтеллектом или не является частью какого-либо сервиса).
Просмотрев таблицуна трезвую голову внимательно, можно составить примерный перечень способов организации кроссдоменных запросов для кроссбраузерного юзерскрипта:
Недостатки:
Полное описание объекта можно найти на сайте Greasespot.
Нам же необходимо знать, что GM_xmlHttpRequest является аналогом XMLHttpRequest и предоставляет такой же программный интерфейс.
Функция для посылки запроса может выглядеть так (применён хак setTimeout, чтобы обойти ошибку безопасности при обращении из небезопасного окна к коду юзерскрипта при выполнении запроса):
Это событие актуально только для Opera. Вызывается, когда в документе появляется элемент скрипта перед его выполнением. Событие можно перехватить и остановить выполнение скрипта. Чем мы и воспользуемся.
Важно: Для Opera нужно поставлять отдельный файл, в котором будет осуществляться навешивание события. Это связано с особеннностями выполнения пользовательских скриптов. Обратите внимание: в дополнительном скрипте не должно быть метаданных! Название скрипта начинается с нижнего подчеркивания, чтобы скрипт загружался первым.
Ссылка на дополнительный скрипт:_opera-xdr-engine.js
Код дополнительного скрипта на pastebin.com.
Запрос осуществляется вызовом следующей функции:
Замечание: Для Opera существует ещё одно решение: тыц. Я его не ковырял, но вероятно оно лучше представленного здесь.
Реализация JSONP остаётся в качестве домашнего задания :)
Благо, работающих примеров в сети предостаточно.
Но прежде всего нужно задаться вопросом: нужна ли вам вообще поддержка вашего юзерскрипта в IE?
Для осуществления запросов в Хроме вам необходимо упаковать юзерскрипт в расширение.
Подробно данный метод описан в предыдущей статье. Там же дан пример проксирования кроссдоменного запроса (вызов функции запроса можно найти в оболочке, ниже по тексту).
Еслилень переходить по ссылке вы читали статью и знаете, как упаковать скрипт, то код для background.html доступен на pastebin.
Все перечисленные выше способы собраны в оболочку.
Код не претендует на звание «лучший код 2011», но является рабочим и используется в различных модификациях в коммерческих юзерскриптах (да-да, бывают и такие).
Код оболочки можно найти на pastebin.com.
Кроссдоменный запрос осуществляется вызовом
Определение нужного транспорта происходит автоматически.
Сегодня мы рассмотрим варианты организации кроссдоменных запросов в юзерскриптах.
В подробности реализации того или иного механизма я вдаваться не буду, но приведу пример кроссбраузерной оболочки для кроссдоменных запросов.
Вступление
Как известно, в чистом виде в естественной среде браузерного окружения кроссдоменные запросы — штука не тривиальная (благодаря Same origin policy).
Поддержка XMLHttpRequest с CORS есть не во всех браузерах (в опере вообще до сих пор не встречена).
JSONP позволяет только GET-запросы, а проксирование через фреймы заставляет использовать сторонние библиотеки, либо писать жуткие велосипеды.
Перерыв:Если вы дочитали до этого места, и не поняли ни слова, то сделайте перерыв, погуглите неизвестные термины, выпейте чаю. Не унывайте, дальше будут объяснения «на пальцах» и с кодом. Начинающие скриптописатели могут вздохнуть спокойно: вдаваться в подробности мы не будем, но рабочий код и капля теории со всеми ссылками будет в вашем «загашнике».
Основы
В чем проблематичность кроссдоменных запросов? Все браузеры ограничивают нашу свободу в угоду безопасности. Посему, запросы из «недоверенных» источников пресекаются на корню. А что делать, если мы источникам доверяем? Правильно, использовать «костыли» (многие из которых являются общепринятой практикой).
В рамках юзерскриптов следует учитывать ограничения, накладываемые окружением, в котором запускаются скрипты (подробности в этой статье) плюс дополнительное важное условие: наличие доступа к серверной части (наличие (или возможность создать) серверного API для реализации конкретного метода запроса)!
Ниже приведена таблица, в которой представлены некоторые «костыли» и их применимость для юзерскриптов.
Название метода + ссылка | Краткое описание | Требует доступ к серверу | Можно использовать в юзерскриптах |
---|---|---|---|
JSONP Статья на Хабре |
Только GET-запросы. Информация запрашивается посредством вставки в тело документа тега <script>. Ответ сервера попадает в тело скрипта и исполняется браузером. При этом, в скрипте должна быть определена функция-«обёртка», которая передаётся с сервера и содержится в ответе. |
Требуется доступ или JSONP API |
IE7+ Opera Firefox |
XHR + CORS Статья на Хабре Статья на Mozilla Hacks |
Запрос осуществляется посредством XMLHttpRequest (XHR) с указанием специальных заголовков запроса. |
Требуется доступ или XHR CORS API |
IE8+ Firefox Chrome (extension) |
iframe транспорт |
Запрос осуществляется через размещение в документе невидимого айфрейма, который возвращает ответ в родительское окно. Довольно запутанный способ. |
Требуется доступ. Удобнее всего использовать библиотеку easyXDM (нужна небольшая модификация для Chrome и Firefox). |
IE7+ Firefox Opera Chrome (extension) |
Родные возможности юзерскриптов |
Специфичны для каждого браузера. В IE отсутствуют как класс. Firefox + GreaseMonkey предоставляют GM_xmlHttpRequest (аналог XMLHttpRequest), GET+POST запросы. Chrome предоставляет полноценный кроссдоменный XMLHttpRequest, но только для расширений, GET+POST запросы. У Opera есть событие beforeScript, при помощи которого можно осуществить GET-запрос через <script> (не JSONP, следовательно, доступ к серверу не нужен). |
Не требуется доступ к серверу. |
Firefox Opera Chrome (extension) |
Для подавляющего большинства скриптов критичным параметром является наличие доступа к серверу. К тому же, чаще всего используются GET-запросы (если скрипт не зловред, не наделён мегаинтеллектом или не является частью какого-либо сервиса).
Просмотрев таблицу
- Chrome = упаковка + проксирование XMLHttpRequest (описано в третьей статье)
- Firefox + GreaseMonkey = использование GM_xmlHttpRequest
- Opera = использование события beforeScript и скрипт-транспорта
- IE7+ = использование JSONP
Недостатки:
- Только GET-запросы (не критично для 90%)
- Для IE нужен доступ к серверу или JSONP API (не критично для 90%, для остальных можно решить через YQL)
- Нетривиальная обработка ошибок транспорта
- Для оперы понадобится дополнительный файл
Подробнее о GM_xmlHttpRequest
Полное описание объекта можно найти на сайте Greasespot.
Нам же необходимо знать, что GM_xmlHttpRequest является аналогом XMLHttpRequest и предоставляет такой же программный интерфейс.
Функция для посылки запроса может выглядеть так (применён хак setTimeout, чтобы обойти ошибку безопасности при обращении из небезопасного окна к коду юзерскрипта при выполнении запроса):
var GMTransport = function(url, onDone){ setTimeout(function(){GM_xmlhttpRequest({ method : "GET", url : url, onload : function(x) { var o = x.responseText; if (onDone) { onDone(o); } } });},0); }
BeforeEvent
Это событие актуально только для Opera. Вызывается, когда в документе появляется элемент скрипта перед его выполнением. Событие можно перехватить и остановить выполнение скрипта. Чем мы и воспользуемся.
Важно: Для Opera нужно поставлять отдельный файл, в котором будет осуществляться навешивание события. Это связано с особеннностями выполнения пользовательских скриптов. Обратите внимание: в дополнительном скрипте не должно быть метаданных! Название скрипта начинается с нижнего подчеркивания, чтобы скрипт загружался первым.
Ссылка на дополнительный скрипт:_opera-xdr-engine.js
Код дополнительного скрипта на pastebin.com.
Запрос осуществляется вызовом следующей функции:
var scriptTransport = function(url, onDone){ var t = document.createElement("script"); t.src = url; t._callback = onDone; document.body.appendChild(t); }
Замечание: Для Opera существует ещё одно решение: тыц. Я его не ковырял, но вероятно оно лучше представленного здесь.
JSONP
Реализация JSONP остаётся в качестве домашнего задания :)
Благо, работающих примеров в сети предостаточно.
Но прежде всего нужно задаться вопросом: нужна ли вам вообще поддержка вашего юзерскрипта в IE?
Разбираемся с Chrome
Для осуществления запросов в Хроме вам необходимо упаковать юзерскрипт в расширение.
Подробно данный метод описан в предыдущей статье. Там же дан пример проксирования кроссдоменного запроса (вызов функции запроса можно найти в оболочке, ниже по тексту).
Если
Оболочка
Все перечисленные выше способы собраны в оболочку.
Код не претендует на звание «лучший код 2011», но является рабочим и используется в различных модификациях в коммерческих юзерскриптах (да-да, бывают и такие).
Код оболочки можно найти на pastebin.com.
Кроссдоменный запрос осуществляется вызовом
xdr.xget(url, callback);
Определение нужного транспорта происходит автоматически.
- Учимся писать userscript'ы
- Userscripts. Углубляемся
- Userscripts. Упаковываем юзерскрипт для Chrome
- » Usersctripts. Кроссдоменные запросы