Вероятно, лучшее междоменное решение...  

внешний интерфейс
Вероятно, лучшее междоменное решение...  

Сегодня поговорим на общую тему, кроссдоменность!

Опять междоменный, раздражает? В Интернете так много междоменных статей, что глаза устают.🤣 Не уходи... Я постараюсь максимально просто объяснить всем несколько распространенных междоменных решений.Я верю, что после внимательного прочтения этой статьи, будь то в качестве испытуемого или интервьюера в будущем, вы иметь все знания по этой теме.Смогу сделать это с легкостью.

Что такое «кросс-происхождение»

Разве это не о междоменном? Почему существует еще один «кросс-происхождение»? Вы можете делать ошибки?

😄...Не теряйте терпения. На самом деле то, что мы обычно называем междоменным, — это узкий сценарий запроса. Проще говоря, это означает «пересечение».Политика одинакового происхождения браузераЗапросить ресурс «источник», так мы называем его «кросс-источник», не проблема. Так,

Кросс-происхождение, какой источник?Политика одинакового происхождения браузера

Что такое гомология?Протокол, доменное имя и порт одинаковы, то есть источник один и тот же.

Каннаба, можешь дать каштан?Каштаны :), некоторые и некоторые:

const url = 'https://www.google.com:3000'

Например, приведенный выше URL-адрес, протокол:https, доменное имя **www.google.com**, порт 3000.

А если источник другой?Будет много ограничений, таких как:

  • Cookie, LocalStorage, IndexDB и другой сохраненный контент не могут быть прочитаны
  • Узел DOM недоступен
  • Был сделан Ajax-запрос, но ответ был перехвачен браузером

Я только хочу кое о чем спросить, а для чего, почему ты хочешь меня таким ограничивать?Из соображений безопасности без него вы можете столкнуться:

  • Перехват файлов cookie, данные, украденные вредоносными веб-сайтами
  • Более уязвим для XSS, CSRF-атак
  • Невозможно поместить в карантин потенциально вредоносные файлы
  • ... ...

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

✘ Access to XMLHttpRequest at 'xxx' from origin 'xxx' has been block by CORS,
  policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

Это чувство отправки и получения отсутствия ответа - это как ограничение таинственной восточной силой, когда вы занимаетесь серфингом в Интернете:EC2519D9-DA3E-422F-B130-6120E846E088.pngЭто очень неудобно, поэтому давайте посмотрим, как использовать научный метод для серфинга в Интернете (Аааа, научный метод решения междоменных проблем).

JSONP

Эта вещь используется<script>помеченАтрибут src не имеет уязвимости междоменного ограниченияТак что мы можем получить данные JSON динамически генерироваться из других источников.

Почему он называется JSONP?JSONP - это аббревиатура JSON with Padding, эээ, а что касается того, почему он так называется, стандартного объяснения в интернете я не нашел, и надеюсь, что братья в области комментариев это знают и быстро подскажут :)

Как этого добиться?Конкретные идеи реализации можно условно разделить на следующие этапы.:

  • Сценарий на этом сайте создает элемент с адресом src, указывающим на сервер, запрашивающий данные между доменами.
  • Предоставьте функцию обратного вызова для приема данных, имя функции можно согласовать, передав параметр адреса
  • После того, как сервер получает запрос, он возвращает строку ответа, обернутую данными JSON, например: callback({...})

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

function jsonp({ url, params, callback }) {
  return new Promise((resolve, reject) => {
    // 创建一个临时的 script 标签用于发起请求
    const script = document.createElement('script');
    // 将回调函数临时绑定到 window 对象,回调函数执行完成后,移除 script 标签
    window[callback] = data => {
      resolve(data);
      document.body.removeChild(script);
    };
    // 构造 GET 请求参数,key=value&callback=callback
    const formatParams = { ...params, callback };
    const requestParams = Object.keys(formatParams)
      .reduce((acc, cur) => {
        return acc.concat([`${cur}=${formatParams[cur]}`]);
      }, [])
	  .join('&');
	// 构造 GET 请求的 url 地址
    const src = `${url}?${requestParams}`;
    script.setAttribute('src', src);
    document.body.appendChild(script);
  });
}

// 调用时
jsonp({
  url: 'https://xxx.xxx',
  params: {...},
  callback: 'func',
})

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

<script src='https://xxx.xxx.xx?key=value&callback=xxx'><script>

Хотите увидеть пример?кликните сюда

Преимущества JSONP — простота и хорошая совместимость, но и недостатки очевидны.Требуется поддержка сервера и поддерживаются только запросы GET., давайте рассмотрим второе решение, которое в настоящее время также является основным междоменным решением.фокус! 😁

CORS

CORS(Совместное использование ресурсов между источниками) полное имяСовместное использование ресурсов между источниками, имя очень высокое, не бойтесь, эта штука на самом деле механизм. В браузере нет политики одного и того же происхождения, хорошо это или нет, но это не очень удобно для разработчиков, потому что нам часто может понадобиться инициироватьHTTP-запрос между источниками. Как мы уже говорили ранее, междоменный запрос действительно был отправлен, но браузер его перехватил, потому что это было, грубо говоря, небезопасно, т.к.Вы хотите получить что-то с сервера без разрешения. Так как же быть в безопасности? Если сервер позволяет, значит безопасно, принцип реализации CORS:Используйте дополнительные заголовки HTTP, чтобы сообщить браузерам, что веб-приложениям, работающим в одном источнике, разрешен доступ к указанным ресурсам с разных исходных серверов..

совместимость

В настоящее время все основные браузеры поддерживают CORS, среди них версия браузера IE не может быть ниже 10,IE 8 и 9 должны делать это через XDomainRequest.

Ситуация полной совместимости?кликните сюда

Принцип реализации

CORS требует поддержки как браузера, так и сервера. Весь процесс связи CORS автоматически завершается браузером.

что за автомат?

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

еслипростой запрос, добавитOriginПоле, указывающее, от кого пришел этот запросисточник. После того, как сервер получит запрос, он вернет ответ, а заголовок ответа будет содержатьAccess-Control-Allow-Originполе, его значениеЛибо доменное имя, указанное в заголовке Origin, либо символ «*»., что означает, что принимаются запросы с любого доменного имени. Если такого поля в заголовке ответа нет, значит, текущий источник не входит в разрешенную область действия сервера, и браузер сообщит об ошибке:

GET /cors HTTP/1.1
Origin: https://xxx.xx
Accept-Language: en-US
Connection: keep-alive
... ...

еслине простой запрос, отправитПредполетный запрос (preflight), цель состоит в том, чтобы узнать у сервера, находится ли доменное имя текущей веб-страницы в списке разрешений сервера и какие HTTP-глаголы и поля заголовка можно использовать. Браузер выдаст формальный запрос только в том случае, если получит положительный ответ, в противном случае он сообщит об ошибке. Вы можете обнаружить, что в нашей ежедневной разработке мы увидим много запросов, инициированных с использованием метода OPTION, который на самом деле является предварительным запросом:

OPTIONS /cors HTTP/1.1
Origin: http://xxx.xx
Access-Control-Request-Method: PUT
Accept-Language: en-US
... ...

Итак, какие запросы являются простыми, а какие — сложными?

тип запроса

Что не запускает предварительную проверку CORS, так это простой запрос. Какие запросы не запускают предварительную проверку?

Используйте один из следующих методов:GET, HEAD, POST,

а такжеContent-TypeЗначение ограничено одним из следующих трех:

  • text/plain
  • multipart/form-data
  • application/x-www-form-urlencoded

И наоборот, запрос, который не соответствует вышеуказанным условиям, является непростым запросом.

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

PostMessage

PostMessage — это API в Html5 XMLHttpRequest Level 2, который реализуетОбмен сообщениями между документами. Совместимость, IE8+, Chrome, Firfox и другие основные браузеры поддерживаются, вы можете использовать их с уверенностью 😊, как понять междокументное взаимодействие?

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

window.postMessage(message, origin, [transfer])

Метод postMessage принимает три параметра: сообщение для отправки, источник для получения сообщения и необязательный объект Transferable.Как получать сообщения?

window.addEventListener("message", function receiveMessage(event) {}, false); // 推荐,兼容性更好

window.onmessage = function receiveMessage(event) {} // 不推荐,这是一个实验性的功能,兼容性不如上面的方法

После получения сообщения событие объекта сообщения содержит три свойства:источник, происхождение, данные, где data — это сообщение, которое мы отправили.

Кроме того, помимо реализации оконной связи, postMessage также может взаимодействовать с Web Worker и Service Work.кликните сюда.

Websocket

Websocket — это постоянный протокол HTML5, онРеализуйте полнодуплексную связь между браузером и сервером, а также междоменное решение. Что такое полнодуплексная связь? Проще говоря,То есть после установления соединения и сервер, и клиент могут активно отправлять или получать данные друг другу..

Нативный WebSocket API не очень удобен в использовании, мы обычно выбираем инкапсулировать Websocket самостоятельно (ну, наша команда тоже инкапсулировала: )) или использовать существующую стороннюю библиотеку, здесь мы используем стороннюю библиотеку.wsНапример:

const WebSocket = require('ws');

const ws = new WebSocket('ws://www.host.com/path');

ws.on('open', function open() {
  ws.send('something');
});

ws.on('message', function incoming(data) {
  console.log(data);
});
... ...

Следует отметить, что Websocket — это длинное соединение, и установка нескольких Websocket-соединений на одной странице может вызвать проблемы с производительностью.

Обратный прокси Nginx

Мы знаем, что политика одного и того же источника ограничивает: стандарты, которым должны следовать браузеры при отправке запросов из разных источников на серверы, если этоСервер отправляет междоменный запрос на серверШерстяная ткань?

Ответ, конечно,Не ограничен политикой браузера в отношении одного и того же происхождения..

После использования этой идеи мы можем настроить прокси-сервер для получения клиентских запросов, а затем пересылает запрос на сервер, чтобы получить ответ, а затем пересылать ответ на клиента:

017D8331-6CD1-4E43-A912-7D21B7B04E45.png

Это принцип обратного прокси-сервера Nginx, который может обеспечить междоменный доступ с помощью простой настройки:

# nginx.config
# ...
server {
  listen       80;
  server_name  www.domain1.com;
  location / {
    proxy_pass   http://www.domain2.com:8080;  #反向代理
    proxy_cookie_domain www.domain2.com www.domain1.com; #修改cookie里域名
    index  index.html index.htm;

    # 当用 webpack-dev-server 等中间件代理接口访问 nignx 时,此时无浏览器参与,故没有同源限制,下面的跨域配置可不启用
    add_header Access-Control-Allow-Origin *;
    add_header Access-Control-Allow-Credentials true;
    # ...
  }
}

Прокси промежуточного программного обеспечения узла

Принцип реализации такой же, как принцип прокси-сервера, о котором мы упоминали ранее, за исключением того, что здесь в качестве прокси используется промежуточное ПО Node. должны знать о том,Браузеры по-прежнему следуют политике одного и того же источника при отправке запросов к прокси-серверам., не забудьте выполнить междоменную обработку через CORS на уровне Node:

const https = require('https')
// 接受客户端请求
const sever = https.createServer((req, res) => {
  ...
  const { method, headers } = req
  // 设置 CORS 允许跨域
  res.writeHead(200, {
    'Access-Control-Allow-Origin': '*',
    'Access-Control-Allow-Methods': '*',
    'Access-Control-Allow-Headers': 'Content-Type',
    ...
  })
  // 请求服务器
  const proxy = https.request({ host: 'xxx', method, headers, ...}, response => {
    let body = ''
    response.on('data', chunk => { body = body + chunk })
    response.on('end', () => {
      // 响应结果转发给客户端
      res.end(body)
    })
  })
  // 结束请求
  proxy.end()
})

document.domain

Если доменное имя второго уровня совпадает, установка document.domain может привести к междоменному использованию.Что такое второе доменное имя?

a.test.com и b.test.com — домены второго уровня, которые являются поддоменами test.com. Как добиться кросс-доменности?

document.domain = 'test.com' // 设置 domain 相同

// 通过 iframe 嵌入跨域的页面
const iframe = document.createElement('iframe')
iframe.setAttribute('src', 'b.test.com/xxx.html')
iframe.onload = function() {
  // 拿到 iframe 实例后就可以直接访问 iframe 中的数据
  console.log(iframe.contentWindow.xxx)
}
document.appendChild(iframe)

Суммировать

Конечно, помимо приведенных выше схем, сравниваяHackТакже:window.name, location.hash, но эти междоменные методы теперь устарели, почему? потому чтоНапротив, в качестве альтернативы есть более безопасный и мощный PostMessage.. На самом деле существует множество междоменных решений.

  • CORS поддерживает все HTTP-запросы и является наиболее распространенным решением для разных доменов.
  • JSONP поддерживает только запросы GET, но совместим со старыми браузерами.
  • И промежуточное ПО Node, и обратный прокси-сервер Nginx используют межсерверное взаимодействие без ограничений политик одного и того же источника.
  • Websocket также является междоменным решением.
  • PostMessage может обеспечить связь между документами, больше для связи в окне
  • document.domain, window.name, location.hash постепенно уходят из исторической сцены, как альтернатива PostMessage хорошее решение

напиши в конце

Эта статья впервые появилась на моемблог, нехватка знаний и знаний, неизбежны ошибки, и я надеюсь, что статья неверна и меня поправят!

Если у вас есть какие-либо вопросы или вы нашли ошибки, вы можете задать вопросы или опечатки в соответствующих выпусках

Если вам нравится или у вас есть вдохновение, добро пожаловать в звезду, что также является поощрением для автора.

(над)