Задача:
— есть REST-сервер
— есть одно страничное приложение (HTML/CSS/Javascript) которое берет данные с сервера через XMLHttpRequest
— нужно разработать новую фичу
Когда перед front-end разработчиком стоит такая задача на вскидку есть два варианта:
— поднять тестовый сервер у себя на localhost
— попросить Back-end добавить в ответ сервера заголовок «Allow-Control-Allow-Origin: *» что-бы использовать XMLHttpRequest2
Первый вариант затратен по времени, и не всегда возможен. Второй вариант тоже не лучший — ставить «Allow-Control-Allow-Origin: *» вроде как не безопасно, да и back-end может это делать долго.
И тут мне пришла в голову вроде бы тривиальная идея — а зачем менять на сервере заголовки, если это можно сделать прямо на клиенте.
Про Fiddler я уже пробовал писать когда-то.
— На вкладке «Filters» Включаем Use filters
— включаем «Set response header» и добавляем нужный заголовок «Allow-Control-Allow-Origin: *»
Все!
Боюсь что если бы на этом статья закончилась публика не оценила бы, и заминусовала меня и пост чуть менее чем полностью, поэтому далее идет решение для тех кто не хочет иметь ничего общего с Фидлером и кто не ищет легких путей.
Среди расширений для Хрома мне почему-то не попалось ни одного, которое могло бы изменять Response-заголовки, хотя возможно я плохо искал. Поэтому решил по быстрому написать свой велосипед. ссылка на расширение и github ведь это модно и молодежно
{ "name": "Allow-Control-Allow-Origin: *", "version": "1.0", "manifest_version": 2, "description": "Allow to you request any site with ajax from any source. Add to response - 'Allow-Control-Allow-Origin: *' header", "background": { // собственно подключили скрипт нашего расширения "scripts": ["background.js"] }, "browser_action": { //добавим кнопку расширения с картинкой и заголовком, "default_popup" мне не нужен "default_icon": "off.gif", "default_title": "Allow-Control-Allow-Origin" }, "permissions": [ "storage", // для localStorage "webRequest", //для webRequest API "webRequestBlocking", "*://*/*" //хочу посылать запросы на любой адрес ], "web_accessible_resources": [ //ресурсы расширения - чтобы не писать полный путь к картинке когда мы ее будем менять "on.gif","off.gif" ] }
Чуть более подробно:
— «background» — один, два вкратце — для того чтобы расширение работало при запуске Хрома в фоне.
В «permissions»: [ "*://*/*"] указывается адреса сайтов где расширение работает и куда есть доступ послать ajax-запрос из расширения. Альтернатива «content_scripts»: […],
если нужно встроить скрипт прямо на страницы открытого сайта (полезно если нужно использовать функции и переменные объявленные в скриптах сайта, иначе расширение работает в своей области видимости а скрипты сайта в своей)
— «browser_action» — Нужен чтобы добавить кнопочку включения и выключения расширения
альтернатива «page_action»
одновременно page_action и browser_action использовать нельзя
— webRequest API и webRequestBlocking — подменять заголовки запроса и ответа
— «web_accessible_resources» — иначе путь к картинке должен выглядеть так:
нужно путь:
background-image:url("/sprites.png");
CSS
background-image:url(‘chrome-extension://__MSG_@@extension_id__/sprites.png’);
JS
var url = chrome.extension.getURL(‘sprites.png’);
backgound.js
var requestListener = function(details){ var flag = false, rule = { name: "Origin", value: "http://evil.com/" }; for (var i = 0; i < details.requestHeaders.length; ++i) { if (details.requestHeaders[i].name === rule.name) { flag = true; details.requestHeaders[i].value = rule.value; break; } } if(!flag) details.requestHeaders.push(rule); return {requestHeaders: details.requestHeaders}; }; var responseListener = function(details){ var rule = { "name": "Access-Control-Allow-Origin", "value": "*" }; details.responseHeaders.push(rule); return {responseHeaders: details.responseHeaders}; }; /*On install*/ chrome.runtime.onInstalled.addListener(function(){ localStorage.active = false; }); /*Icon change*/ chrome.browserAction.onClicked.addListener(function(tab){ if(localStorage.active === "true"){ localStorage.active = false; chrome.browserAction.setIcon({path: "off.gif"}); /*Remove Response Listener*/ chrome.webRequest.onHeadersReceived.removeListener(responseListener); chrome.webRequest.onBeforeSendHeaders.removeListener(requestListener); }else{ localStorage.active = true; chrome.browserAction.setIcon({path: "on.gif"}); /*Add Response Listener*/ chrome.webRequest.onHeadersReceived.addListener(responseListener,{ urls: [ "*://*/*" ] },["blocking", "responseHeaders"]); chrome.webRequest.onBeforeSendHeaders.addListener(requestListener,{ urls: [ "*://*/*" ] },["requestHeaders"]); } });
Подробнее по коду:
Callback’и для onHeadersReceived и onBeforeSendHeaders вынес в отдельные функции responseListener и requestListener соответственно для того что бы после включении и выключении плагина заголовки не подменялись. Удаляем навешенные обработчики
chrome.runtime.onInstalled — выполнится один раз — там можно инициализировать default состояние плагина
chrome.browserAction.onClicked.addListener — когда клацаем по кнопке расширения — отлавливаем событие и имитируем включение и выключение плагина
if(localStorage.active === «true») — почему-то я каждый раз спотыкаюсь на этом и забываю что ключи в localStorage хранятся в <String>
По сути onBeforeSendHeaders нам не нужен, но так как Хром не дает отсылать с localhost ajax-запросы пришлось добавить.
В первой версии расширения я этого не заметил так как при запуске хрома у меня стоит флаг —allow-file-access-from-files
Подробнее про флаги можно почитать тут и тут
У меня стоят такие:
Правой кнопкой по ярлыку -> Properties -> Targets
C:\Users\Ololo\AppData\Local\Google\Chrome\Application\chrome.exe —allow-file-access-from-files —remote-debugging-port=9222 —allow-file-access —allow-cross-origin-auth-prompt
Что касается FF — почему-то и здесь я не нашел расширений для подмены ответа от сервера, но опять же может плохо искал. Если кто подскажет вставлю в пост.
P.S.
Я надеюсь вам пригодится расширение или совет. У тех кому это показалось банально и не достойно хабра я прошу прощения, но как минимум одному человеку это было не так очевидно как вам и стало полезно (мне).
У меня есть сомнения по поводу безопастности, по идее с включенным расширением можно с любого сайта забивать на CORS, но мы ведь все честные и будем использовать это только для разработки.
ссылка на оригинал статьи http://habrahabr.ru/post/166539/
Добавить комментарий