Сводка интерфейсных междоменных методов

внешний интерфейс сервер браузер
Сводка интерфейсных междоменных методов

Зачем нужен междоменный

Из соображений безопасности браузеры ввели политику одного и того же происхождения. Эта стратегия ограничит ресурсы доступа js, выполняемого на нашей странице, например, мы не можем напрямую обращаться к DOM-структуре страницы из разных источников через js, и мы не можем получить содержимое ответа сервера при отправке запросов к разным источникам ( сервер обработает запрос в обычном режиме и вернет содержимое ответа, но возвращенное содержимое будет перехвачено браузером). Здесь также используется понятие «источник».Если протокол, доменное имя и порт целевого URL-адреса, который мы посещаем, и URL-адрес, на котором находится текущая страница, различаются, они считаются принадлежащими двум разным источникам. Разобравшись с определением источника, давайте посмотрим, что мы можем и чего не можем делать на странице под действием политики того же источника.

Давайте поговорим о том, что мы можем сделать в первую очередь, например, перенаправить нашу страницу через js (изменив location.href), отправить форму, все это возможно. Кроме того, можно загрузить необходимые нам ресурсы, внедрив некоторые теги HTML, такие как теги сценария для введения сценария, теги img для вставки изображения, теги ссылок для загрузки файлов стилей, iframe для встраивания страниц из разных источников и скоро. Это также нормальные операции в нашем ежедневном процессе разработки.

Однако политика того же источника ограничивает доступ js к некоторым конфиденциальным ресурсам. В дополнение к двум пунктам, упомянутым в начале, контент, хранящийся в файлах cookie и LocalStorage, которые не принадлежат одному и тому же источнику, не может быть доступен в js. В частности, существуют тонкие различия между файлами cookie и LocalStorage в управлении доступом к источникам. Родительский домен может настроить файл cookie, чтобы разрешить поддоменам доступ к этому файлу cookie при настройке файла cookie. В то же время файл cookie связан только с доменом. имя и путь. Источники с одним и тем же доменным именем и разными портами по-прежнему используют файлы cookie под одним и тем же доменным именем, в то время как LocalStorage управляется на основе источника за источником и не зависит друг от друга. Различные источники не могут получить доступ к содержимому в LocalStorage из друг друга.

Общие междоменные методы

Взаимодействие клиента и сервера

Проблема связи между клиентом и сервером из разных источников — очень распространенная проблема, которую необходимо решать в обычном процессе разработки, в основном следующими способами:

CORS

Этот метод следует использовать чаще. Полное название CORS — Cross-Origin Resource Sharing, что переводится как совместное использование ресурсов между источниками. Основная идея состоит в том, чтобы ввести некоторый пользовательский заголовок HTTP для завершения связи между клиентом и сервером.

Для некоторых простых запросов браузер отправит запрос с заголовком запроса Origin, указывающим текущий источник.Сервер не будет проверять, является ли текущий источник запроса законным при обработке запроса, но все равно обработает запрос и ответит в обычном режиме. конец, браузер. Получив ответ, он проверит, есть ли источник текущей страницы в списке Access-Control-Allow-Origin ответа сервера, если нет, он напрямую заблокирует текущий запрос.

С точки зрения браузера запросы, отвечающие следующим условиям, считаются простыми запросами:

Метод запроса — GET или POST; Содержит только Accept, Accept-Language, Content-Language или Content-Type (значениеapplication/x-www-form-urlencoded,multipart/form-data, илиtext/plainЗаголовок в остальном как простой заголовок;

Для непростых запросов браузер сначала отправит на сервер предварительный запрос, который использует метод Option и содержит следующий заголовок:

  1. Origin
  2. Access-Control-Request-Method: Спросите сервер, поддерживается ли метод;
  3. Access-Control-Request-Headers: Спросите сервер, поддерживает ли он непростые заголовки, включенные в запрос;

Последние два заголовка будут отображаться только в предварительных запросах. Затем браузер получает ответ сервера, содержащий следующий заголовок:

  1. Access-Control-Allow-Origin
  2. Access-Control-Allow-Methods: отвечает клиенту списком методов запроса, поддерживаемых сервером;
  3. Access-Control-Allow-Headers: заголовок, поддерживаемый сервером в ответ на запрос клиента;

На этом Preflight запрос подошёл к концу, после чего браузер проверит, есть ли источник текущего запроса в списке источников, перечисленных в Access-Control-Allow-Origin ответа сервера, и если он то есть реальный запрос будет отправлен. Во время эксперимента браузер не обязательно отправляет реальный запрос, если сервер поддерживает метод запроса и заголовок запроса Preflight request.Пока источник запроса является законным, он отправит запрос после запроса Preflight.

JSONP

Полное название JSONP — JSON with Padding, что переводится как заполненный JSON. При указании запрашиваемого URL интерфейс может согласовать с сервером параметр, определяющий имя функции обратного вызова, чтобы гарантировать, что функция обратного вызова, указанная интерфейсом, вызывается во фрагменте скрипта бэкенда. end response, чтобы можно было отправлять несколько запросов JSONP, не мешая друг другу. Конкретная реализация JSONP выглядит следующим образом:

var delicious_callbacks = {};
function jsonp(url, callback) {
  var uid = (new Date()).getTime();
  delicious_callbacks[uid] = function (data) {
    delete delicious_callbacks[uid];
    callback(data);
  };
  url += "?jsonp=" + encodeURIComponent("delicious_callbacks[" + uid + "]");
  var script = document.createElement('script')
  script.src = url
  document.body.appendChild(script)
};

jsonp("http://example.com/api", function(data) { // here we get the data });

Сам JSONP имеет определенные недостатки, очевидно, что его можно использовать только для GET-запросов. Кроме того, серверное приложение может столкнуться с ошибками 4xx, 5xx или столкнуться с другими непредвиденными ситуациями в процессе обработки, что приведет к невозможности вернуть строку в правильном формате вызова функции js, поэтому необходимо отслеживать событие onerror тег script для обработки возможных непредвиденных ситуаций.

Совместное использование файлов cookie между доменами

В качестве решения для хранения на стороне клиента существует несколько способов установки файлов cookie на стороне клиента:

  1. Настройте сервер для возврата заголовка ответа Set-Cookie.
  2. С помощью document.cookie в коде JavaScript на странице установка document.cookie непосредственно для содержимого, которое нам нужно сохранить, не перезапишет существующий файл cookie, например:
document.cookie="name=Jack;path=/"
document.cookie="age=25;path=/" // cookie中会同时保存name和age这两个字段

У файла cookie есть срок действия. Если срок действия файла cookie не задан явным образом, как в приведенном выше коде, соответствующий файл cookie также будет очищен после выхода из браузера.

В обычных условиях браузер автоматически отправляет файл cookie, соответствующий текущему имени домена и пути к серверу, при посещении страницы. Как правило, запрос Ajax, который мы отправляем на странице, не будет автоматически отправлять файл cookie, связанный с текущим URL-адресом, на сервер вместе с запросом. Если нам нужно отправить файл cookie с текущим посещенным URL-адресом на сервер в запросе, мы можем установить для свойства withCredentials объекта XMLHttpRequest значение true.

Если вы хотите отправить cookie доменного имени текущей страницы на сервер под другим доменным именем, вам необходимо настроить сервер для поддержки CORS, и вам нужно обратить внимание на Access-Control-Allow, возвращаемый сервером в настоящее время.-Origin больше не может быть установлен в '*', и сервер должен вернуть Access-Control-Allow-Credentials: true, иначе ответ сервера все равно будет заблокирован браузером.

После этой настройки браузер будет сопоставлять атрибут пути под доменным именем текущей страницы с запрошенным URL-адресом при отправке Ajax-запроса, содержащего учетную информацию (то есть файл cookie) (например, URL-адрес текущего запроса /test/ Например, файлы cookie, установленные по путям /, /test/, /test/example, будут отправлены вместе с файлами cookie, отправленными на сервер. Таким образом реализуется междоменный обмен файлами cookie.

Связь между страницами

В дополнение к необходимости взаимодействовать с серверами различного происхождения, мы также сталкиваемся с проблемами связи между страницами, нам необходимо получить доступ к некоторой информации на других страницах или сохранить некоторые данные для доступа к другим страницам. Конкретные методы заключаются в следующем:

document.domain

Таким образом, два источника, которые пересекают домены, должны соответствовать определенным условиям, то есть доменные имена двух источников должны быть связаны между родительским и дочерним доменами или одним и тем же доменом. Потому что значение параметра страницы document.domain может быть только самим текущим доменом или родительским доменом, но не другими несвязанными доменными именами. Только когда для document.domain двух страниц установлено одно и то же значение, страница, встроенная в iframe, и страница, загруженная iframe, могут получать информацию о странице друг друга (включая структуру DOM, объект окна и т. д.).

На практике также есть две проблемы, на которые необходимо обратить внимание:

  1. Если источник двух страниц один и тот же, они могут взаимодействовать напрямую, но если доменное имя двух страниц одинаковое, но порт другой или другие ситуации, то для двух страниц все равно необходимо установить один и тот же document.domain. , иначе они все равно будут просматриваться. Устройство заблокировано. Конкретные причины также упоминаются на MDN:

Браузер сохраняет номер порта отдельно. любая операция присваивания, в том числеdocument.domain = document.domainприведет к перезаписи номера порта наnull. следовательноcompany.com:8080не просто установивdocument.domain = "company.com"прийти сcompany.comкоммуникация. Он должен быть назначен на обеих сторонах, чтобы убедиться, что номер портаnull.

  1. Необходимо связаться с загруженной подстраницей после загрузки встроенного iframe, иначе полученное значение может быть неопределенным.

свойство имени оконного объекта

У браузеров есть такая особенность: страницы, загруженные в одну и ту же вкладку или в один и тот же iframe, имеют одно и то же значение свойства window.name, что означает, что пока это страница, открытая в той же вкладке (независимо от того, является ли она одной и той же origin или нет), значение свойства window.name одинаково на этих страницах. Используя эту функцию, вы можете использовать это свойство в качестве среды для передачи данных между разными страницами.

Если данные передаются между двумя источниками без связи между родительским и дочерним доменами с помощью iframe+window.name (при условии, что источник A хочет получить данные из источника B), iframe на странице источника A загружает цель источника B После страницы (страница-источник Б задает данные по атрибуту window.name), ему нужно перейти на определенную страницу-источник А, чтобы могла пройти страница, встроенная в iframe (описано выше) и страница в iframe будет задокументируйте документ. .domain все настроены на источник A, чтобы получить данные в iframe. Пример кода выглядит следующим образом:

// www.a.com/getData.html
<script type="text/javascript">
function getData() {
  var frame = document.getElementsByTagName("iframe")[0];
  frame.onload = function () {
    var data = frame.contentWindow.name;
    // 此处获取数据
    alert(data);
  };
  frame.contentWindow.location = "./aaa.html";
  // 加载完www.b.com/data.html之后就加载www.a.com/下随便一个页面,获取数据
}
</script>
<iframe src="http://www.b.com/data.html" style="display: none;" onload="getData();"></iframe>

HTML5 cross-document message

Еще один способ обмена сообщениями между страницами был введен в HTML5 и называется обмен сообщениями между документами. Он также может реализовать передачу данных между главной страницей и встроенной подстраницей iframe (или страницей, открытой текущей страницей).Кроме того, этот метод также может использоваться для завершения обмена данными между текущим потоком движка JavaScript и другими рабочие нити. Если он предназначен для связи с подстраницей, загруженной через iframe, вам необходимо сначала получить объект окна целевой страницы, которая получает данные (в частности, полученные с помощью метода, упомянутого выше), и метод postMessage объекта может отправить данные на целевую страницу.

<!--send.html-->
<iframe src="./receiver.html" id="frame"></iframe>
<button id="send-btn">send message</button>
<script>
  var frame = document.getElementById('frame')
  document.getElementById('send-btn').addEventListener('click', function() {
    frame.contentWindow.postMessage({
      name: 'Jack'
    }, 'http://localhost:8888') // 接收信息的页面所在的源
  })
</script>

<!--receiver.html-->
<script>
  window.addEventListener('message', function(e) {
    // 验证消息发送方所在的源
    if(e.origin === 'http://localhost:8888') {
      console.log(e.data)
      e.source.postMessage(...) // 回送消息
    }
  })
</script>

Если необходимо пообщаться с воркером на странице, напрямую вызвать метод postMessage созданного экземпляра Worker.В скрипте, выполняемом экземпляром Worker, получить доступ к экземпляру Worker через self или this, а затем вызвать метод postMessage для завершения связи.

localStorage

localStorage — это решение для хранения на стороне клиента, представленное в HTML5. Содержимое, хранящееся через localStorage, всегда будет храниться на стороне клиента. Если для явного удаления содержимого не будет вызван метод removeItem, оно будет сохранено навсегда. В представлении localStorage на MDN также упоминается метод реализации localStorage в браузерах, которые не поддерживают localStorage с помощью файлов cookie.Установив время истечения срока действия файла cookie в точке в будущем, можно имитировать постоянное сохранение localStorage.При имитации localStorage для удаления сохраненного контента будет использоваться соответствующий файл cookie. Далее, если не задать время истечения куки, его также можно использовать для имитации другой схемы хранения на стороне клиента в браузере — sessionStorage. В отличие от файлов cookie, localStorage обеспечивает больший предел емкости хранилища.

Как упоминалось ранее, контент, хранящийся в localStorage, управляется источником, а это означает, что даже если имя домена одинаково, страницы с разными портами не могут обмениваться данными через localStorage. Откройте несколько страниц одного происхождения на нескольких вкладках браузера. Объект окна на этих страницах может прослушивать событие хранилища. Когда страницы других вкладок устанавливают содержимое в localStorage, событие будет инициировано для уведомления. коммуникация страницы также может быть достигнута таким образом.

Другие междоменные проблемы

загрузка файла шрифта

Существует также междоменная проблема при загрузке файлов шрифтов, на которые ссылается CSS, поэтому необходимо настроить CORS для загрузки файлов шрифтов в других доменах. По умолчанию определение нового шрифта не приводит к немедленной загрузке соответствующего файла шрифта. Соответствующий файл шрифта будет загружен только тогда, когда элемент на странице использует этот шрифт.

Обработка ошибок сценариев с разными источниками

Для ошибок выполнения скрипта из разных источников, загруженных на страницу, функция обработки ошибок window.onerror, привязанная к странице, по умолчанию не может получить конкретную информацию об ошибке. origin script., то есть выполнять CORS при запросе междоменных сценариев. Значения, которые можно установить для атрибута crossorigin:

  1. анонимно: учетные данные не передаются при запросе скриптов
  2. use-credentials: использовать учетные данные при запросе скриптов.

Любое другое значение будет рассматриваться как анонимное ключевое слово. Установка атрибута crossorigin означает, что сервер также необходимо настроить для поддержки CORS. Если CORS не настроен должным образом на сервере, междоменные сценарии не могут быть загружены в обычном режиме.

Преобразование содержимого рисунка холста в файловый объект

Динамически загружаемые изображения в холсте можно рисовать непосредственно в холсте, но также возникают междоменные проблемы при преобразовании холста в файловые объекты для работы, и будет возникать ошибка «Невозможно экспортировать испорченные холсты». В это время вам необходимо установить свойство crossOrigin динамически загружаемого объекта изображения, а также настроить сервер для поддержки CORS.

let img = new Image()
img.crossOrigin = 'anonymous'
img.src = "//localhost:8888/images/1751527990314_.pic.jpg"
img.onload = () => {
  let canvas = document.getElementById('canvas')
  let ctx = canvas.getContext('2d')
  ctx.drawImage(img, 0, 0)
  canvas.toBlob(blob => console.log(blob), 'image/jpeg', .75)
}

Суммировать

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