0,0
рейтинг
19 декабря 2009 в 00:54

Разработка → Авторесайз IFRAME и безопасный способ передачи информации с одного домена на другой

Как известно, при работе с фреймами для обеспечения безопасности браузеры не позволяют JavaScript-коду обращаться со страницы одного домена на страницу другого домена. В этой краткой статье мы рассмотрим аспекты кросс-доменной работы в JavaScript, опишем один из «хороших» частных случаев, а в конце — я надеюсь в хабракомментах получить ответы на оставшиеся вопросы.

UPD1: те, кто здесь впервые, — обязательно читайте комментарии к этой статье, в них очень много интересного накидали (как я и надеялся). Спасибо!

UPD2: найдено решение задачи авторесайза для всего, кроме Opera < 10.

UPD3: полностью кроссбраузерное решение задачи с ресайзом приводится ниже. Его особенности: а) не портится history, б) работает даже в Опере 7 и IE6, в) для ускорения работы высота фрейма всегда делается кратной N=30 пикселям. Фактически, там 2 алгоритма — для IE (через location.hash) и для «не-IE» (через window.name и «простукивание» возможных высот в цикле). См. также комментарии к статье, там разъяснения, почему так, а не иначе.

UPD4: статья начала принимать черты монументальной, посему она переехала ко мне в Наблы на dkLab: dklab.ru/chicken/nablas/58.html — там же все примеры кода самой последней актуальности. Но, конечно, в случае изменений я буду их и тут тоже анонсировать, добавляя UPD5, UPD6 и т.д.
Дмитрий Котеров @DmitryKoterov
карма
385,2
рейтинг 0,0

Самое читаемое Разработка

Комментарии (71)

  • 0
    Ээх… Сталкивался с проблемой точь в точь такой же (подгрузка страницы в ифрейм и изменение размеров этого ифрейма чтобы избавиться от скролла). Решения не нашел :(
    Ставлю 1$ что его не существует :)
    • +9
      P.S. Кстати заметил, что в свете последних публикаций «ставьте картинки в топики, чтоб их больше смотрели», топиков с картинками резко прибавилось :)
    • +1
      Мало ставите, чтобы способ появился =)
    • +1
      Гоните бакс. :-)
      • 0
        Жду координаты ;)
  • +1
    Написал вот и тут же родилась идея:

    Страница slave.com/frame.html:
    top.location = top.location + "#height=1000"

    Кто проверит, работает ли? (Нет сейчас сервера под рукой.)
    • –1
      не работает.

      вот этот вариант работает:
      parent.document.getElementById('iframe').style.height='1000px';
      • 0
        Это не сработает, когда parent на другом домене, чем iframe.
  • +12
    Посмотрите тут
    • +5
      черт, удалите срочно. Доллар то не лишний! )
      • 0
        Какой доллар, о чём речь? )
        • 0
          первый комментарий ;)
          • +1
            А, ну тогда Вы проиграли :) Зато сможете изменять размеры фреймов :)
    • +3
      Вот она, сила хабра. Спасибо!
      • 0
        Недавно сам таким же занимался просто, исследовал варианты. Правда остановился на server-side proxy.
  • +4
    есть доступ к обоим доменам?
    softwareas.com/cross-domain-communication-with-iframes

    или JSONP
  • +1
    Что за девушка на фото? О:)
    • +1
      похожа на Дженнифер Лав Хьюитт :)
      • 0
        Тоже так сначала подумал. Похожа
        • 0
          Она и есть.
      • 0
        Обладательница высшей фигуры…
    • НЛО прилетело и опубликовало эту надпись здесь
      • 0
        Не читал статью, но из-за Boobs-эффекта :)
  • НЛО прилетело и опубликовало эту надпись здесь
    • НЛО прилетело и опубликовало эту надпись здесь
    • +6
      а ты думал под катом будет весь фотосет?
      • НЛО прилетело и опубликовало эту надпись здесь
  • +1
    Почему бы просто не создать тег script и не подгрузить в него JS с другого домена?
    • НЛО прилетело и опубликовало эту надпись здесь
      • +1
        Да, пожалуй. Я признаю, что могут быть специфические случаи, когда в соседний фрейм идёт приличный кусок данных, нужный и основном документе.
    • 0
      Есть и другая причина, почему тэг script на другой домен — не всегда хорошо: скрипт можно подменить на злоумышленный, и в итоге можно получить все куки главного домена и их куда-нибудь сохранить. Не всегда владелец master.com хочет, чтобы владелец slave.com видел его куки.
      • 0
        Не спорю, есть масса различных ограничений и всякий способ хорош в своём случае. Описанный автором вообще работает в рамках одного домена второго уровня.

        Кстати, Дим, я тебе написал в «Моём круге», но ты что-то так и не ответил.
  • 0
    Давно есть уже сервисы, которые работают и не знают, что с другого домена грузить JS нельзя :) Например, type comment, которым регулярно пользуюсь…
  • НЛО прилетело и опубликовало эту надпись здесь
    • 0
      А что это за хак? Можно ссылочку?
      • НЛО прилетело и опубликовало эту надпись здесь
        • +1
          Так не сработает, top.name с другого домена недоступен.

          Однако про хак с window.name удалось нарыть кое-что интересное:
          development.lombardi.com/?p=611
          easyxdm.net/wiki/Default.aspx (а это вообще универсальная библиотека для кросс-доменного общения)
          • 0
            И еще отличный пост вот этот: habrahabr.ru/blogs/javascript/41669/
            Там интересный прием с about:blank (интересно, работает ли он во всех браузерах).
          • НЛО прилетело и опубликовало эту надпись здесь
            • 0
              Кстати, очень остроумная идея. К сожалению, заметить изменения через for (var k in top.frames) не удается — в FireFox при смене window.name это изменение не создает новый ключ в top.frames. Однако если сделать for (var i = 300; i < 5000; i++) if (top.frames[«frm» + i]) doSomething() (т.е. перебрать все мыслимые размеры IFRAME вручную), то ключ удается обнаружить. В частности, это работает в Опере 7!

              Но, к сожалению, не работает в IE8 (может, и в более ранних тоже). В них изменение window.name вообще не влияет на top.frames.
              • НЛО прилетело и опубликовало эту надпись здесь
          • НЛО прилетело и опубликовало эту надпись здесь
  • +1
    фотка хорошая )
  • 0
    document.domain может также порождать проблемы. например, невозможно создать в DOM новый ифрэйм без указания src и положить туда произвольный контент, так как у свежесозданного ифрэйма не будет document.domain
  • +2
    На одном фрилансерском ресурсе предлагали 15 тысяч долларов за решение подобной задачи, но без возможности вставить произвольный яваскрипт на странице master.com. Я так и не смог придумать решение:(
    • 0
      Интересно там решили ?:) Ссылочку найдете? :)
      • 0
        www.elance.com/c/rfp/main/rfpBid.pl?jobid=16695520
        Пожалуйста, правда я немного сумму приврал:) К сожалению биды размещаются закрыто, поэтому узнать о решении вряд ли выйдет.

        Вкратце: есть магазин, который продает навороченные шаблоны для ebay-магазинов. Главная их фишка была в том, что стиль изменял полностью внешний вид страницы, включая формочки и контролы ebay, но после того как ebay измененил систему шаблонов, пользовательская страница стала помещаться во фрейме, который находится на другом домене и соответственно магазин потерял свою главную фишку.
  • НЛО прилетело и опубликовало эту надпись здесь
  • 0
    poll.rufox.ru — не совсем то, но все же…
  • 0
    а в чем проблема? передаем высоту ifram в параметрах урла этого самого iframe. итого вложенный ифрэйм знает какая у него высота.
  • –1
    Если не секрет, какое отношение картинка имеет к статье?
    • +1
      это несчастный iframe с порнушкой, который (-ая) не может получить доступ к родительской странице :)
      • НЛО прилетело и опубликовало эту надпись здесь
  • +1
  • 0
    можно сделать кросс доменный аякс запрос через dynamic script tag hack
    на хабре есть про это стаитьи
  • –1
    Да, была у меня в молодости идея хакнуть гугл (реализовать клики по «своей» рекламе), но только разрушилась, узнав о проблеме доступа к функциям в iframe. А потом узнал еще о некоторых хитростях гугла в этом направлении и забросил идею…

    А так — не тот бы был сейчас гугл )))
  • 0
    Насчет метода с якорем (fragment) в top.location — увы, он не работает в Опере младше 10-й версии. Почему-то при добавлении якоря к location убиваются все события на странице (включая setTimeout), так что нет никакой возможности обнаружить, что якорь появился (а также при добавлении якоря страница иногда перезагружается с сервера).
  • 0
    Добавил в статью UPD2 — решение про авторесайз IFRAME. Увы, в Опере младше 10 версии — это не работает, будет бесконечный цикл перезагрузки страницы.
  • 0
    Можно и так
  • 0
    Кажется, есть первый кандидат на кроссбраузерное решение (дописал UPD3 в конце статьи).
  • 0
    отлично. только сегодня искал способ авторесайза iframe'a — и вот решения :)
  • 0
    У меня есть хорошее готовое решение для этой проблемы. Есть поддержка переходов по страницам внутри ифрэйма, поддержка динамического изменения высоты. С удовольствием опубликовал бы, но кармы не хватает. Сколько кармы нужно, чтобы опубликовать хотя бы в личный блог?
  • 0
    Странно, что никто не упомянул про то, что почти все решения описаны здесь и здесь. Правда по поводу XhrIframeProxy там не совсем точно описано, а готовое решение можно посмотреть в исходниках dojo toolkit. Когда мне это всё понадобилось, долго думал по поводу необходимости иметь специальную html страничку(с js кодом, который реализует передачу данных) на обоих доменах, что не всегда возможно, лучшее что придумал — подгрузить хостовую страницу ещё раз… Но это лишний клиентский траффик, накрутка рекламы и посещаемости. Если всеми данными недостатками не заморачиваться — вроде бы работает. По поводу Opera — точно не скажу, возможно не во всех версиях, но можно проверить. К тому же dojo обещает кроссбраузерность.
  • 0
    Думаю, что стоит отметить одну особенность браузера FF 3.6.13 + кроссдоменное решение от Дмитрия.
    Если есть переходы внутри фрейма, тогда после нескольких переходов, в списке top.frames будут доступны все фреймы, по которым прошелся пользователь, а потому, во время «простукивания» возможных высот в цикле будет учитываться самый маленький по высоте фрейм.

    Смотрел еще в:
    Opera 11.00 — все ok;
    Chrome 8.0.552.224 — все ok.
  • 0
    а если внутри iframe происходит переход на другие страницы и при этом изменяется высота контента?
  • 0
    В ИЕ если ходить по ссылкам внутри ифрэйми то каждый раз от куда-то нужно получать УРЛ внешнего окна для кода
    top.location.replace("http://master.com/#h" + h);
    таким образом информацию полученную из «ret» при инициализации ифрэйма
    iframe src="http://slave.com/iframe.html?ret=http://master.com/"
    нужно где-то сохранять. Или в куку писать, или в тотже window.name прописывать и использовать window.name как хранилище.

    И ещё, этот код внутри ифрэйма (когда в отдельно окне, то всё ОК) document.body.scrollHeight, при переходу по ссылкам, возвращает максимальное из ранее полученных высот (такое поведение во многих браузерах). Таким образом ифрэйм может только растягиваеться.

    Вобщем из-за кучи особенностей, из-за которых можно внезапно отхватить пришлось отказаться от этого подхода.

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.