предисловие
Полагаю, каждому фронтенду знакомо слово кросс-доменный, и оно используется во многих практических проектах, но от разнообразия кросс-доменных методов голова кружится.Некоторое время назад у моих коллег в компании были кросс-доменные проблемы , и какое-то время они не могли их найти. К проблеме, поэтому вот краткое изложение междисциплинарных знаний, статья с базовыми упражнениями в 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
динамическое созданиеscript
label, чтобы мы могли гибко вызывать удаленные сервисы, то мы просто преобразуем следующую страницу 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