Вы действительно понимаете кроссдомены?

внешний интерфейс
Вы действительно понимаете кроссдомены?

предисловие

Полагаю, каждому фронтенду знакомо слово кросс-доменный, и оно используется во многих практических проектах, но от разнообразия кросс-доменных методов голова кружится.Некоторое время назад у моих коллег в компании были кросс-доменные проблемы , и какое-то время они не могли их найти. К проблеме, поэтому вот краткое изложение междисциплинарных знаний, статья с базовыми упражнениями в 4D Web от поверхностного к глубокому

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

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

Адрес сборника статей:isboyjc/блог Портал

что такое кросс домен

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

Фактически, некоторые скачки ресурсов, такие как ссылка, перенаправление и отправка формы, например<link>、<script>、<img>、<frame>Дождитесь тега dom и в стилеbackground:url()、@font-face()Другие внешние ссылки на встроенные файлы, такие как некоторые запросы ajax, инициированные js, междоменные операции объектов dom и js и т. д., являются междоменными.

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

Политика одинакового происхождения браузера

Политика того же происхождения/SOP (политика того же происхождения)NetscapeКомпания представила браузер в 1995 г. Это основная и самая основная функция безопасности браузера.Если политика того же происхождения отсутствует, браузер уязвим для атак.XSS, CSFRждать атаки

Гомологичный, каков источник? источник относится к协议、域名、端口, то один и тот же источник означает, что все три одинаковы, даже если разные доменные имена указывают на один и тот же IP-адрес, разные источники

Давайте посмотрим на состав доменного имени, начнем сhttp://www.hahaha.com/abc/a.jsНапример

  • http:// --> протокол
  • www --> поддомен
  • hahaha.com --> основное доменное имя
  • 80 --> порт (http://Порт по умолчанию 80)
  • abc/a.js --> запрос пути к ресурсу

Итак, давайте возьмем источник этого доменного имени в качестве примера для сравнения со следующим

URL результат причина
http://www.hahaha.com/abc/b.js гомология только путь разный
http://www.hahaha.com/def/b.js гомология только путь разный
https://www.hahaha.com/abc/a.js разные источники разные протоколы
http://www.hahaha.com:8081/abc/a.js разные источники разные порты
http://aaa.hahaha.com/abc/a.js разные источники разные хосты

В случае разного происхождения политика одного и того же происхождения ограничивает нас

  • Содержимое хранилища, такое как файлы cookie, LocalStorage, IndexedDB и т. д., не может быть прочитано
  • Узлы DOM и объекты Js не могут быть получены
  • После отправки AJAX-запроса результат перехватывается браузером (обратите внимание, чтоЗапрос был отправлен, результат получен, но он был перехвачен браузером)

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

Различные типы междоменных решений

No.1 междоменный документ.домен+iframe

Введение

document.domainспособ достижения междоменных, применимых сценариев только вОсновное доменное имя такое же, доменное имя подуровня другоев случае

Например, следующие две страницы

http://aaa.hahaha.com/a.html
http://bbb.hahaha.com/b.html

Итак, что он может сделать

  • Обе страницы имеют одинаковые настройкиdocument.domain, общие файлы cookie
  • Обе страницы имеют одинаковые настройкиdocument.domain,пройти черезiframeРеализовать обмен данными между двумя страницами

Пример

Общие файлы cookie

Во-первых, обе страницы настроены на одно и то жеdocument.domain

document.domain = 'hahaha.com';

Страница a устанавливает cookie через скрипт

document.cookie = "test=a";

страница b прочитать этот файл cookie

let cookieA = document.cookie;
console.log(cookieA)

Сервер также может указать доменное имя файла cookie в качестве доменного имени первого уровня при настройке файла cookie, например.hahaha.com

Set-Cookie: key=value; domain=.hahaha.com; path=/

В этом случае доменное имя второго уровня и доменное имя третьего уровня могут читать этот файл cookie без каких-либо настроек.

общие данные
<!--a页面-->
<iframe src="http://bbb.hahaha.com/b.html" onload="load()" id="frame"></iframe>
<script>
  document.domain = 'hahaha.com';
  let a = "this is a";
  
  // 获取b页面数据
  function load(){
    let frame = document.getElementById("frame")
    console.log(frame.contentWindow.b) // this is b
  }
</script>
<!--b页面-->
<script>
  document.domain = 'hahaha.com';
  let b = "this is b"
  
  // 获取a页面数据
  console.log(window.parent.a); // this is a
</script>

ограниченное

  • Во-первых, только если основное доменное имя совпадает, а доменное имя подуровня отличается.
  • Работает только с файлами cookie и окнами iframe, данные LocalStorage и IndexDB не могут быть переданы таким образом.

№ 2 location.hash + перекрестный домен iframe

Введение

Две страницы из разных источников не могут получить DOM друг друга Типичным примером являетсяiframeокно иwindow.openокна, открытые методом, не могут взаимодействовать с родительским окном

Например, страница а и страница б разных источников, если мы напрямую получаем данные друг друга

страница а:http://www.hahaha0.com/a.html

<iframe src="http://www.hahaha1.com/b.html" onload="load()" id="frame"></iframe>
<script>
  let a = "this is a"
  
  // 获取b页面数据
  function load(){
    console.log(document.getElementById("frame").contentWindow.b) 
    // Uncaught DOMException: Blocked a frame from accessing a cross-origin frame.
  }
</script>

страница б:http://www.hahaha1.com/b.html

<!--b-->
<script>
  let b = "this is b"
  
  // 获取a页面数据
  console.log(window.parent.a); // 报错
</script>

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

Давайте посмотрим по-другомуwindow.location.hash, он получает URL#Часть после номера называется идентификатором фрагмента.

Напримерhttp://hahaha.com/a.html#fragmentиз#fragment, если просто поменять идентификатор фрагмента, то страница не обновится, как и используется хеш-роутинг в знаменитом Vue таким образом

пройти черезlocation.hash + iframeМы можем получать данные друг друга в разных основных доменах.

Пример

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

использовать между разными доменамиiframeизlocation.hashПередача по значению, прямой доступ JS между одним и тем же доменом для связи

Тогда наша логика становится следующей

Различные домены a и b могут обмениваться данными только в одном направлении через хеш-значения, а домены b и c также различаются и могут обмениваться данными только в одном направлении, но c и a находятся в одном домене, поэтому c может получить доступ ко всем объектам на страница a через parent.parent

страница а:http://www.hahaha0.com/a.html

<!--a中通过iframe引入了b-->
<iframe id="frame" src="http://www.hahaha1.com/b.html"></iframe>
<script>
  let frame = document.getElementById('frame');

  // 向b传hash值
  frame.src = frame.src + '#a=我是a';

  // 给同域c使用的回调方法
  function cb(data) {
    console.log(data) // 打印 我是a+b
  }
</script>

страница б:http://www.hahaha1.com/b.html

<!--b中通过iframe引入了中间人c-->
<iframe id="frame" src="http://www.hahaha0.com/c.html"></iframe>
<script>
  let frame = document.getElementById('frame');

  // 监听a传来的hash值,传给c.html
  window.onhashchange = function () {
    frame.src = frame.src + location.hash + '+b';
  };
</script>

страница с:http://www.hahaha0.com/c.html

<script>
  // 监听 b 的hash值变化
  window.onhashchange = function () {
    // c调用父亲的父亲,来操作同域a的js回调,将结果传回
    window.parent.parent.cb(location.hash.replace('#a=', ''));
  };
</script>

№ 3 window.name + перекрестный домен iframe

Введение

windowобъект имеетnameАтрибут, этот атрибут имеет характеристику, то есть в течение жизненного цикла окна все страницы, загружаемые окном, совместно используютwindow.name, каждая пара страницwindow.nameиметь права на чтение и запись

window.nameОн сохраняется на всех страницах, загружаемых окном, и не будет сбрасываться при загрузке новой страницы, как в следующем примере.

страница а

<script>
  window.name = '我是a';
  setInterval(function(){
    window.location = 'b.html'; // 两秒后把一个新页面b.html载入到当前的window中
  },2000) 
</script>

страница б

<script>
  console.log(window.name); // 我是a
</script>

В приведенном выше примере мы можем интуитивно увидеть, что после того, как страница a будет загружена в течение 2 секунд, перейдите на страницу b, и b выведет на консоль我是a

ноwindow.nameЗначение может быть только в виде строки, максимально допустимое значение составляет около 2M, в зависимости от разных браузеров, но в целом достаточно

Затем мы можем использовать его функцию для достижения междоменного взаимодействия, посмотрите на заголовок, чтобы узнать, что он должен использовать.window.nameиiframe, тогда вы можете подумать о том, как быть авантюристом, о нет, это умный способ избежать междоменного доступа, не оставляя следов?

Испытав описанное выше уничтожение, мы знаем, что страница и страница b в разных доменных условиях используютiframeВстроить страницу, данные не могут быть переданы, потому что они будут междоменными, здесь мы должны использоватьwindow.name + iframeЧтобы добиться междоменного обмена данными, очевидно, что мы не можем напрямую изменить страницу, изменивwindow.locationЧтобы загрузить страницу b, потому что сейчас нам нужно добиться того, чтобы страница a не прыгала, но также могла получать данные в b

Как этого добиться? Фактически, он все еще должен полагаться на страницу посредника c

Во-первых, посредник c должен принадлежать к тому же домену, что и

страница черезiframeзагружается b , оставляя данные на текущей странице в biframeокноwindow.nameимущество

В настоящее время не может быть прочитанiframe, из-за разных доменов, но мы можем динамически добавлятьiframeизsrcизменить на с

Посреднику c не нужно ничего писать, потому что он напрямую наследует то, что оставляет b.window.name

Поскольку c и a находятся в одном домене, a обычно может получить подстраницу c.window.nameзначение атрибута

Я должен сказать, что этот подход действительно потрясающий, отдать должное предшественникам.

Пример

страница а:http://www.hahaha1.com/abc/a.html

<iframe src="http://www.hahaha2.com/abc/b.html" id="frame" onload="load()"></iframe>
<script>
	let flag = true
  // onload事件会触发2次
  // 第1次onload跨域页b成功后,留下数据window.name,后切换到同域代理页面
  // 第2次onload同域页c成功后,读取同域window.name中数据
  function load() {
    if(flag){
      // 第1次
      let frame = document.getElementById('frame')
      frame.src = 'http://www.hahaha1.com/abc/c.html'
      flag = false
    }else{
      // 第二次
      console.log(frame.contentWindow.name) // 我是b
    }
  }
</script>

страница б:http://www.hahaha2.com/abc/b.html

<script>
  window.name = '我是b'  
</script>

No.4 междоменное окно.postMessage

Введение

Несколько междоменных методов окна, о которых мы упоминали выше, применимы к соответствующим сценариям, безопасны и надежны, но все они оппортунистичны, нет, они являются еще одним сокращением, ноHTML5 XMLHttpRequest Level 2Чтобы решить эту проблему, вводится совершенно новый API: API обмена сообщениями между документами (Cross-document messaging).

Этот APIwindowобъект добавилwindow.postMessageметод, который позволяет сценариям из разных источников взаимодействовать асинхронно с ограниченным взаимодействием, обеспечивая кросс-текстовый документ, многооконный и междоменный обмен сообщениями.

Совместимость с основными браузерами также очень впечатляет.

Давайте посмотрим на его использование, давайте посмотрим, как он отправляет данные

otherWindow.postMessage(message, targetOrigin, [transfer]);
  • otherWindow
    • Ссылка на окно, напримерiframeизcontentWindowсвойства, выполнитьwindow.openвозвращаемый объект окна, именованный или пронумерованный в числовом видеwindow.frames
  • message
    • данные для отправки в другие окна, они будутАлгоритм структурированного клонированияСериализация, что означает, что вы можете безопасно передавать объект данных в целевое окно без каких-либо ограничений, не сериализуя его самостоятельно
  • targetOrigin
    • через окноoriginАтрибут, чтобы указать, какие окна могут получать события сообщения, после указания только соответствующегоoriginОкно ниже может получить сообщение, установленное на подстановочный знак*Указывает, что его можно отправить в любое окно, но обычно это не рекомендуется из соображений безопасности.Если вы хотите отправить в окно с тем же источником, что и текущее окно, вы можете установить для него значение/
  • передача | необязательный атрибут
    • представляет собой строку из иmessageпередается одновременноTransferableОбъекты, право собственности на которые будет передано получателю сообщения, а отправитель больше не сохранит право собственности

Он также может контролироватьmessageВозникновение события для получения данных

window.addEventListener("message", receiveMessage, false)
function receiveMessage(event) {
  let origin= event.origin
  console.log(event)
}

Далее, в случае кроссдоменности в реальном бою, черезwindow.postMessageобмениваться данными

Пример

Или возьмем для примера страницы a и b разных доменов

страница а:http://www.hahaha1.com/abc/a.html, создать перекрестный доменiframeи отправить информацию

<iframe src="http://www.hahaha2.com/abc/b.html" id="frame" onload="load()"></iframe>
<script>
  function load() {
    let frame = document.getElementById('frame')
    // 发送
    frame.contentWindow.postMessage('哈喽,我是a', 'http://www.hahaha2.com/abc/b.html')
    
    // 接收
    window.onmessage = function(e) {
      console.log(e.data) // 你好,我是b
    }
  }
</script>

страница б:http://www.hahaha2.com/abc/b.html, получать данные и возвращать информацию

<script>
  // 接收
  window.onmessage = function(e) {
    console.log(e.data) // 哈喽,我是a
    // 返回数据
    e.source.postMessage('你好,我是b', e.origin)
  }
</script>

Кроссдоменный JSONP № 5

написать впереди

заJSONPХотя эта часть используется редко, мы упомянем ее осторожно, потому что мы столкнулись с некоторыми новичками,AJAXиJSONPперепутал, поднимитеJSONP, скажет очень легко, т.е.AJAXПросто задайте поле в запросе, возможно вы его использовалиJQueryв упаковкеJSONPМеждоменный метод на самом деле просто добавляет поле в запрос, но это всего лишь способ использования инкапсуляции JQ, внешний вид вас не смущает, вы действительно понимаете его принцип (JQ: я не принимаю виноват!!!)

Как работает АЯКС

AjaxПринцип просто через браузерjavascriptобъектXMLHttpRequest(движок Ajax) отправляет асинхронный запрос на сервер и получает данные ответа сервера, а затем используетjavascriptдля управления DOM и обновления страницы

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

Он также очень прост в использовании

一:创建XMLHttpRequest对象,也就是创建一个异步调用对象

二:创建一个新的HTTP请求,并指定该HTTP请求的方法、URL及验证信息

三:设置响应HTTP请求状态变化的函数

四:发送HTTP请求

五:获取异步调用返回的数据

JSONP, JSON?

JSON(JavaScript Object Notation)Его должен хорошо знать каждый, это облегченный формат обмена данными, студенты, которые не понимают, могут перейти наjson.org Узнайте об этом, сделайте это за считанные минуты

иJSONP(JSON with Padding),этонеофициальныйпротокол, который позволяет интеграцию на стороне сервераScript tagsобратно к клиенту черезjavascript callbackРеализуйте междоменный доступ в виде JSONP, это простая форма реализации JSONP, поэтому может быть непонятно, тогда посмотрим, как это работает

Как работает JSONP

Сначала рассмотрим небольшой пример или две страницы a и b в разных доменах.

страница а:http://www.hahaha1.com/abc/a.html

<html>
<head>
    <title>test</title>
    <script type="text/javascript" src="http://www.hahaha2.com/abc/b.html"></script>
</head>
<body>
  <script>
  	console.log(b) // 我是b
  </script>
</body>
</html>

страница б:http://www.hahaha2.com/abc/b.js

var b = "我是b"

Видно, что хотя домены разные, страница a по-прежнему может получить доступ и распечатать переменные на странице b.

В этом небольшом примере мы можем увидеть очень интуитивно<script>Атрибут src тега не подчиняется политике того же происхождения, поэтому можно получить любой скрипт на сервере и выполнить его, чтоJSONPОсновной принцип заключается в том, как он передает данные, давайте просто реализуем

CallBack реализация JSONP

Пример только что говорит о принципе кросс-доменности, и мы говорили о нем раньше.javascript callbackЧтобы добиться междоменного доступа в виде, тогда давайте изменим код, как добитьсяJSONPизjavascript callbackформа

страница а:http://www.hahaha1.com/abc/a.html

<script type="text/javascript">
  //回调函数
  function cb(res) {
      console.log(res.data.b) // 我是b
  }
</script>
<script type="text/javascript" src="http://www.hahaha2.com/abc/b.js"></script>

страница б:http://www.hahaha2.com/abc/b.js

var b = "我是b"

// 调用cb函数,并以json数据形式作为参数传递
cb({
  code:200, 
  msg:"success",
  data:{
    b: b
  }
})

Создайте функцию обратного вызова, затем вызовите эту функцию в удаленной службе и передайте форму данных JSON в качестве параметра, выполните обратный вызов, этоJSONPПростой режим реализации илиJSONPПрототип очень прост, не так ли?

будетJSONДанные заливаются в функцию обратного вызова, теперь понятно почемуJSONPВызовJSON with Paddingбар

Вышеупомянутая реализация очень проста, обычно мы хотим, чтобы этоscriptМетки могут вызываться динамически вместо описанных выше, потому что они фиксируются вHTMLОн выполняется непосредственно при загрузке, что очень негибко.javascriptдинамическое созданиеscriptlabel, чтобы мы могли гибко вызывать удаленные сервисы, то мы просто преобразуем следующую страницу a следующим образом

<script type="text/javascript">
  function cb(res) {
    console.log(res.data.b)  // 我是b
  }
  
  // 动态添加 <script> 标签方法
  function addScriptTag(src){
    let script = document.createElement('script')
    script.setAttribute("type","text/javascript")
    script.src = src
    document.body.appendChild(script)
  }

  window.onload = function(){
    addScriptTag("http://www.hahaha2.com/abc/b.js")
  }
</script>

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

Далее, мы можем счастливо иметь реальное чувствоJSONPслужба называется

Мы используемjsonplaceholderизtodosИнтерфейс в качестве примера, адрес интерфейса выглядит следующим образом

https://jsonplaceholder.typicode.com/todos?callback=?

callback=?Это написание после интерфейса представляет собой имя функции обратного вызова, то есть вы отправляете имя функции обратного вызова, которую вы определили на клиенте, на сервер, и сервер вернет метод с именем функции обратного вызова, которое вы определили, и получитJSONДанные передаются в этот метод для завершения обратного вызова, имя нашей функции обратного вызова называетсяcb, то полный адрес интерфейса будет следующим

https://jsonplaceholder.typicode.com/todos?callback=cb

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

<script type="text/javascript">
  function cb(res) {
    console.log(res)
  }
  
  function addScriptTag(src){
    let script = document.createElement('script')
    script.setAttribute("type","text/javascript")
    script.src = src
    document.body.appendChild(script)
  }

  window.onload = function(){
    addScriptTag("https://jsonplaceholder.typicode.com/todos?callback=cb")
  }
</script>

Видно, что после загрузки страницы данные, возвращаемые интерфейсом, выводятся, а пока посмотрим на реализацию JSONP в JQ.

JQuery-реализация JSONP

По-прежнему используя приведенный выше интерфейс, давайте посмотрим, как JQ получает данные.

$.ajax({
  url:"https://jsonplaceholder.typicode.com/todos?callback=?",   
  dataType:"jsonp",
  jsonpCallback:"cb",
  success: function(res){
    console.log(res)
  }
});

Видно, что для того, чтобы JQ следовалJSONPспособ доступа,dataTypeполе установлено наjsonp,jsonpCallbackФункция атрибута состоит в том, чтобы настроить имя нашего метода обратного вызова.На самом деле, интерьер похож на то, что мы написали выше.

Сравнение JSONP и AJAX

  • В способе вызова

    • AJAXиJSONPОчень похоже, все они запрашивают URL, а затем обрабатывают данные, возвращаемые сервером.
    • такой классJQueryБиблиотека просто ставитJSONPв видеAJAXОдна из форм запроса инкапсуляции, не путать
  • По основному принципу

    • AJAXЯдро проходит черезxmlHttpRequestПолучить внестраничный контент
    • JSONPСуть в том, чтобы динамически добавлятьscriptТег вызывает сценарий JS, предоставленный сервером, с суффиксом.json
  • разница между ними,

    • AJAXРазличные домены будут сообщать об ошибках между доменами, но вы также можете использовать прокси-сервер на стороне сервера,CORSи так далее по доменам, в то время какJSONPБез этого ограничения разные домены в одном домене могут быть
    • JSONPявляется способом или необязательным соглашением,AJAXне нужно использоватьjsonформат для передачи данных 
    • JSONPтолько поддержкаGETпросить,AJAXслужба поддержкиGETиPOST

Наконец, JSONP — это очень старый междоменный метод, и сейчас его почти никто не использует, поэтому мы можем его понять.

Мы надеемся, что при нормальных обстоятельствах этот тег скрипта можно будет вызывать динамически, а не выполнять перед отображением страницы, поскольку он зафиксирован в html, что очень негибко. Мы можем динамически создавать теги сценария через javascript, чтобы мы могли гибко вызывать удаленные службы.

Междоменное совместное использование ресурсов CORS №6

Что такое КОРС?

появлениеCORSРаньше мы использовалиJSONPспособ достижения междоменного, но этот способ ограниченGETпросьба, покаCORSПоявление этой проблемы решило эту проблему для нас, поэтому это стало тенденцией

CORSявляется стандартом W3C, полное название跨域资源共享(Cross-origin resource sharing)

Это позволяет браузерам отправлять запросы на кросс-серверные серверы.XMLHttpRequestзапрос, тем самым преодолеваяAJAXОграничение только для гомологичного использования

CORSИ браузеры, и серверы должны поддерживать эту функцию, в настоящее время практически все браузеры поддерживают эту функцию, и браузеры IE не должны быть ниже IE10.

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

Поэтому осознайтеCORSКлючом к общению является сервер, если сервер настроен на разрешениеCORSинтерфейс, вы можете общаться между источниками, вам нужно знать, как это реализоватьCORSМеждоменная связь, нам также нужно понимать, что браузер делает с каждым запросом

Браузер будетCORSЗапросы делятся на две категории, простые запросы и не очень простые запросы.Браузер обрабатывает эти два запроса по-разному.

простой запрос

Что такое простая просьба, на самом деле ее легко понять и запомнить два

  • Метод запросаHEAD、GET、POSTодин из трех способов
  • Информация заголовка HTTP не превышает следующих полей
    • Accept
    • Accept-Language
    • Content-Language
    • Last-Event-ID
    • Content-Type (ограничено тремя значениямиapplication/x-www-form-urlencoded,multipart/form-data,text/plain)

Пока эти два условия выполняются одновременно, запрос является простым запросом.

Для простых запросов браузер будет напрямую выдавать запрос CORS, то есть автоматически добавлять запрос CORS к информации заголовка запроса.Originполе для указания источника этого запроса (протокол + имя домена + порт), а затем сервер будет решать, соглашаться ли на этот запрос на основе этого значения

не простой запрос

Зная определение простого запроса, непростой запрос относительно прост, потому что, пока это не простой запрос, он не является простым запросом.

В ответ на не простой запрос браузер перед официальным сообщением сделает запрос-запрос, называемый предварительным запросом (preflight), также называемыйOPTIONSзапрос, потому что метод запроса, который он использует,OPTIONS, этот запрос используется, чтобы спросить

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

В этом предварительном запросе информация заголовка, за исключением указания источникаOriginВ дополнение к полю, также будетAccess-Control-Request-Methodполя иAccess-Control-Request-Headersполя, которые соответственно указывают на браузерCORSиспользуется для запросаHTTPМетод запроса и указанный браузерCORSИнформационное поле заголовка, которое запрос пришлет дополнительно, если вы видите его в тумане, не волнуйтесь, давайте рассмотрим пример

Ниже приведен пример запроса AJAX.

let url = 'http://www.hahaha.com/abc'
let xhr = new XMLHttpRequest()
xhr.open('POST', url, true)
xhr.setRequestHeader('X-Token', 'YGJHJHGJAHSGJDHGSJGJHDGSJHS')
xhr.setRequestHeader('X-Test', 'YGJHJHGJAHSGJDHGSJGJHDGSJHS')
xhr.send()

В этом примере мы отправляем запрос POST и добавляем к нему собственный заголовок.X-TokenиX-Testполе, это непростой запрос, потому что добавлено пользовательское поле заголовка запроса

Затем этот непростой запрос будет содержать следующую информацию в заголовке запроса предварительной проверки.

// 来源
Origin: http://www.hahaha.com
// 该CORS请求的请求方法
Access-Control-Request-Method: POST
// 额外发出的头信息字段
Access-Control-Request-Headers: X-Token, X-Test

свойство withCredentials

Запросы CORS не отправляют файлы cookie и данные аутентификации HTTP по умолчанию.

Если вы хотите отправить cookie на сервер, вы должны сначала дать согласие на сервер, указатьAccess-Control-Allow-Credentialsполе

Access-Control-Allow-Credentials: true

Во-вторых, клиент должен открыть запрос в исходном запросе.withCredentialsАтрибуты

xhr = new XMLHttpRequest()
xhr.withCredentials = true

В противном случае, если один из серверов и клиентов не установлен, cookie не будет отправлен или обработан.

Хотя по умолчанию браузеры не отправляют файлы cookie и информацию для аутентификации HTTP, некоторые браузеры все же будут отправлять файлы cookie вместе, и вы также можете явно закрыть их.withCredentials

xhr.withCredentials = false

Обратите внимание, что если вы хотите отправитьCookie,Access-Control-Allow-OriginВ поле нельзя установить звездочку, и в нем должно быть указано четкое доменное имя, соответствующее запрашиваемой странице, и в то же времяCookieПолитика того же происхождения по-прежнему соблюдается, только те, которые установлены с доменным именем сервера.Cookieбудут загружены, другие доменные именаCookieне будут загружены, и (кросс-происхождение) в исходном коде страницыdocument.cookieНе могу прочитать доменное имя сервераCookie, о чем будет сказано ниже

Междоменная конфигурация CORS на стороне сервера

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

Настройте источники, которые разрешают междоменное

Access-Control-Allow-Origin: *

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

Обратите внимание, установите в этом поле значение*очень небезопасно, рекомендуется указать источник и установить его на*номер браузер не отправитCookie, даже если вашXHRуже настроенwithCredentials, не отправитCookie

Настройте методы для разрешения запросов между источниками

Access-Control-Allow-Methods: GET, POST, OPTIONS, PUT...

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

Настройка разрешенных полей заголовка запроса

Access-Control-Allow-Headers: x-requested-with,content-type...

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

Настройте, разрешить ли отправку файлов cookie

Access-Control-Allow-Credentials: true

Это поле является необязательным, и его значение представляет собой логическое значение, указывающее, разрешить ли отправку файлов cookie. По умолчанию файлы cookie не включаются в запросы CORS.

установить какtrue, что означает, что сервер прямо разрешает включить cookie в запрос и отправить на сервер вместе

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

Настройте срок действия этого запроса предварительной проверки

Access-Control-Max-Age: 1728000

Это поле является необязательным и используется для указания срока действия этого запроса предварительной проверки. Единица измерения — секунды. В приведенных выше результатах период действия составляет 20 дней (1 728 000 секунд), что означает, что ответ можно кэшировать в течение 20 дней. дней.В течение этого периода при повторной отправке Для этого запроса интерфейса нет необходимости отправлять предварительный запрос, экономя ресурсы сервера

Распространенные ошибки генерирования междоменных предварительных запросов

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

OPTIONS 404

No 'Access-Control-Allow-Origin' header is present on the requested resource
且 The response had HTTP status code 404

Сервер не настроен на разрешениеOPTIONSзапрос, то код состояния ответа будет 404, когда будет инициирован предварительный запрос, потому что соответствующий адрес интерфейса не может быть найден

Тогда вам может понадобиться найти бэкэнд, скажите ему изящно, пожалуйста, разрешитеOPTIONSпросить

OPTIONS 405

No 'Access-Control-Allow-Origin' header is present on the requested resource
且 The response had HTTP status code 405

Сервер разрешилOPTIONSзапрошен, но заблокирован в некоторых файлах конфигурации (например, в конфигурации безопасности)OPTIONSпросить

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

OPTIONS 200

No 'Access-Control-Allow-Origin' header is present on the requested resource
且 OPTIONS 请求 status 为 200

Сторона сервера позволяетOPTIONSЗапрос не заблокирован в конфигурационном файле, но есть несоответствие при совпадении заголовка

Так называемое сопоставление голов, напримерOriginПроверка заголовков не соответствует или отсутствует какая-либо поддержка заголовков (например,X-Requested-Withд.), то серверResponseВернитесь к внешнему интерфейсу, и внешний интерфейс сработает, когда обнаружит это.XHR.onerror, что приводит к ошибке

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

OPTIONS 500

Это еще проще, сервер дляOPTIONSПроблема с запрошенным кодом или нет ответа

тогда вам может понадобиться найти серверную часть, которая будетNetworkОтправьте ему скриншот сообщения об ошибке в

No.7 Междоменный прокси-сервер Nginx

междоменное решение iconfont

Браузерный междоменный доступjs/css/imgЭто разрешено политикой того же источника при ожидании обычных статических ресурсов, ноiconfontфайлы шрифтов, такие какeot|otf|ttf|woff|svgисключение, на данный моментNginxДобавьте следующую конфигурацию на сервер статических ресурсов, чтобы решить

location / {
  add_header Access-Control-Allow-Origin *;
}

Междоменный интерфейс обратного прокси-сервера

Мы знаем, что политика одного и того же происхождения простобраузерполитика безопасности, неHTTPчасть протокола, вызовы на стороне сервераHTTPИнтерфейс просто используетHTTPПротокол, не будет выполнять сценарии JS, не требует политики одного и того же происхождения, и нет проблемы пересечения

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

Так мы можем пройтиNginxНастраиваем прокси-сервер, обратный прокси-доступ к междоменным интерфейсам, а также можем модифицироватьCookieсерединаdomainинформация, удобная для текущего доменаCookieнаписать

NginxНа самом деле это разнообразные настройки, простые и легкие в освоении, даже если вы никогда не прикасались к ним, разобраться несложно, давайте рассмотрим на примере

Во-первых, если наша страница a находится вhttp://www.hahaha.comдомен, но наш интерфейс находится вhttp://www.hahaha1.com:9999под доменом

Затем мы запускаем страницу aAJAXПри запросе он будет междоменным, тогда можно пройтиNginxНастройте прокси-сервер, имя домена и страница а совпадают, обаhttp://www.hahaha.com, используйте его как плацдарм для обратного прокси-доступаhttp://www.hahaha1.comинтерфейс

# Nginx代理服务器
server {
  listen       80;
  server_name  www.hahaha.com;

  location / {
    # 反向代理地址
    proxy_pass   http://www.hahaha1.com:9999;  
    # 修改Cookie中域名
    proxy_cookie_domain www.hahaha1.com www.hahaha.com; 
    index  index.html index.htm;
		
    # 前端跨域携带了Cookie,所以Allow-Origin配置不可为*
    add_header Access-Control-Allow-Origin http://www.hahaha.com;  
    add_header Access-Control-Allow-Credentials true;
  }
}

Да, считается, что эта конфигурация прокси никогда не менялась.NginxВы также можете видеть, что большинство из них — это то, что мы упоминали выше, не так ли просто?

Междоменный прокси-сервер No.8

NodeВнедрить междоменный прокси сNginxПричина та же, это запуск прокси-сервера, как и у насVue-CLIНастройка междоменного, по сути, тожеNodeЗапустите прокси-сервис, посмотрим, как это сделать дальше

Несколько конфигураций прокси в Vue-CLI

Vue-CLI основан наwebpackДа, черезwebpack-dev-serverЗапустите скаффолдинг локально, то есть запустите локальныйNodeслужбы, для мониторинга и упаковки и компиляции статических ресурсов в режиме реального времени.Поскольку они все упакованы, их нужно только настроить.Мы находимся вvue.config.jsАгент конфигурации в середине выглядит следующим образом, есть много способов написать, и перечислены несколько распространенных вариантов.

использовать

module.exports = {
  //...
  devServer: {
    proxy: {
      '/api': 'http://www.hahaha.com'
    }
  }
}

Как показано выше, когда вы запрашиваете/api/abcинтерфейс будет проксирован наhttp://www.hahaha.com/api/abc

использовать два

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

module.exports = {
  //...
  devServer: {
    proxy: [{
      context: ['/api1', '/api2', '/api3'],
      target: 'http://www.hahaha.com',
    }]
  }
}

использовать три

Поскольку мы впервые использовали прокси, прокси имел/api, окончательный результат проксиhttp://www.hahaha.com/api/abc, но иногда мы не хотим проксировать при передаче/api, то вы можете использовать следующий метод,pathRewriteатрибут для перезаписи пути

module.exports = {
  //...
  devServer: {
    proxy: {
      '/api': {
        target: 'http://www.hahaha.com',
        pathRewrite: {'^/api' : ''}
      }
    }
  }
}

В настоящее время,/api/abcинтерфейс будет проксирован наhttp://www.hahaha.com/abc

использовать четыре

По умолчанию наш прокси не принимается для запуска наHTTPSна внутреннем сервере с недействительным сертификатом

Если вы хотите принять, вам нужно установитьsecure: false,следующее

module.exports = {
  //...
  devServer: {
    proxy: {
      '/api': {
        target: 'https://www.hahaha.com',
        secure: false
      }
    }
  }
}

использовать пять

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

module.exports = {
  // ...
  devServer: {
    proxy: {
      "/api": {
        target: 'http://www.hahaha.com',
        changeOrigin: true,
      }
    }
  }
}

использовать шесть

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

module.exports = {
  // ...
  devServer: {
    proxy: {
      "/api1": {
        target: 'http://www.hahaha1.com',
        changeOrigin: true
      },
      "/api2": {
        target: 'http://www.hahaha2.com',
        pathRewrite: {'^/api2' : ''}
      },
      "/api3": {
        target: 'http://www.hahaha3.com',
        changeOrigin: true,
        pathRewrite: {'^/api3' : ''}
      }
      // ...
    }
  }
}

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

Node реализует прокси-сервер

Здесь мы используемexpress + http-proxy-middlewareДля создания прокси-сервера используйтеhttp-proxy-middlewareЭто промежуточное ПО не имеет никакого другого значения, просто потому, чтоwebpack-dev-serverиспользуется в

let express = require('express')
let proxy = require('http-proxy-middleware')
let app = express()

app.use('/', proxy({
    // 代理跨域目标接口
    target: 'http://www.hahaha1.com:9999',
    changeOrigin: true,

    // 修改响应头信息,实现跨域并允许带cookie
    onProxyRes: function(proxyRes, req, res) {
        res.header('Access-Control-Allow-Origin', 'http://www.hahaha.com')
        res.header('Access-Control-Allow-Credentials', 'true')
    },

    // 修改响应信息中的cookie域名,为false时,表示不修改
    cookieDomainRewrite: 'www.hahaha.com'
}))

app.listen(3000)

Междоменный WebSocket № 9

Введение в веб-сокеты

WebSocketЭто протокол для полнодуплексной связи по одному TCP-соединению. Он родился в 2008 году и был установлен IETF в качестве стандарта в 2011 году.RFC 6455, и поRFC7936Дополнительные спецификации,WebSocket APIТакже стандартизирован W3C

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

Возможности веб-сокета

  • Построенный на протоколе TCP, реализация на стороне сервера относительно проста.

  • Он имеет хорошую совместимость с протоколом HTTP, порты по умолчанию также 80 и 443, а протокол HTTP используется на этапе рукопожатия, поэтому его нелегко экранировать во время рукопожатия, и он может проходить через различные прокси-серверы HTTP.

  • Формат данных относительно легкий, потери производительности невелики, а связь эффективна.

  • Может отправлять текст или двоичные данные

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

  • Идентификатор протоколаws(если зашифровано,wss), URL-адрес сервера — это URL-адрес

следующее

ws://www.hahaha.com:80/abc/def

Пример

на языковую пару сервераwebsocketЕсть соответствующая поддержка, способ написания другой, здесь мы используемNodeподать пример

На стороне клиента мы можем напрямую использовать HTML5.websocket API, сервер также может использоватьnodejs-websocketвыполнитьwebsocket server, но это не рекомендуется, потому что роднойWebSocket APIЕго немного сложно использовать, и он не идеален для совместимости с браузером, поэтому мы используемSocket.io, который красиво инкапсулируетwebSocketинтерфейс, который обеспечивает более простой и гибкий интерфейс, но также не поддерживаетwebSocketбраузеры обеспечивают обратную совместимость, используяSocket.ioреализация библиотекиwebsocket, при отправке данных вы можете напрямую отправлять сериализуемые объекты, вы также можете настраивать сообщения и использовать строки событий, чтобы различать разные сообщения, весь процесс разработки будет намного удобнее

Чтобы узнать больше, посетите официальный сайтSocket.io - Портал, посмотрим пример

Клиент:http://www.hahaha.com/a.html

<script src="/socket.io/socket.io.js"></script>
<script>
  let socket = io.connect('http://www.hahaha1.com:3000')
  
  socket.on('my event', (data) => {
    console.log(data) // { hello: 'world' }
    
    socket.emit('my other event', { my: 'data' })
  })
</script>

Сервер:http://www.hahaha1.com:3000

const app = require('express').createServer()
const io = require('socket.io')(app)

app.listen(3000)

io.on('connection', (socket) => {
  socket.emit('my event', { hello: 'world' })
  
  socket.on('my other event', (data) => {
    console.log(data) // { my: 'data' }
  })
})

Как показано выше, с помощьюSocket.ioПослеwebsocketЛегко ли подключиться? Следуйте документации и попробуйте сами

Наконец

Всем желаю обратить внимание на паблик "Нерегулярный Фронтенд", и время от времени публиковать статьи, и никаких навороченных акций и рекламы.Надеюсь, что каждый может нажать на статью по желанию, и вы сможете увидеть полный галантереи, или вы можете напрямую добавить заметки о друзьях-роботах «Внешний интерфейс | Бэкэнд | Полный стек» автоматически пройдет, добавьте группу общения, пообщайтесь, пожалуйтесь, решите проблемы и подружитесь, конечно, технология является основным

По таймлайну выложил несколько постов с полным резюме.Есть и другие тривиальные статьи,и больше выкладывать не буду.Эти статьи все написаны одинаково,и может быть плагиат и взаимное обучение.Это все Это неизбежно.Когда я писал эту статью, я также использовал эти статьи для справки, но я снова набрал пример и использовал свое собственное понимание, чтобы закодировать его.На это ушла неделя свободного времени, и содержание было написано автором ниже.есть некоторые сходства,это действительно беспомощно,можно сказать,что есть только так много точек знаний,резюме у всех немного отличается,и грамматика выражения оставлена,мне тоже неудобно,и я специально нашла средство для выявления сходства,чтобы не было недопонимания,ведь мне тоже очень противны носильщики.Ну это очередная поздняя ночь.Я наконец-то закончила работу и легла спать.А,кстати,это не легко закодировать слова.Пожалуйста, как это.Если есть какие-либо ошибки, пожалуйста, укажите, спасибо за вашу поддержку.

Справочная статья

Политика одинакового происхождения браузера и как этого избежать - Ruan Yifeng - 2016.04

Подробное объяснение CORS для междоменного совместного использования ресурсов - Ruan Yifeng - 2016.04

Фронтальная междоменная сортировка — не бойтесь - 2016.10

Стандартные междоменные решения для внешнего интерфейса (полное) - 2017.07

Правильно сталкиваясь с междоменными объектами, не паникуйте - Nuggets Neal_yang - 2017.12

Принципы реализации девяти междоменных методов (полная версия) - Ищу программиста - 2019.01

9 распространенных интерфейсных кросс-доменных решений (подробно) — ищут программиста - 2019.07