Чтобы обеспечить актуальность и точность контента, вы можетеПосмотреть исходный текст
Cross-domain — это сложное и сложное знание, которое часто встречается в повседневной разработке, почему бы не обобщить и не попрактиковать его, и я не буду беспокоиться об этом впредь.
Та же политика происхождения
Причина, по которой существуют междоменные решения, заключается в ограничениях политики одного и того же источника. Политика одного и того же происхождения предусматривает, что если протокол, доменное имя и порт двух URL-адресов не совпадают, они считаются перекрестными. Например, в следующей таблице перечислены иhttp://127.0.0.1:3000
Сравните результаты анализа гомологии,
url | результат | причина |
---|---|---|
http://127.0.0.1:3000/index | гомология | |
https://127.0.0.1:3000 | перекрестное происхождение | разные протоколы |
https://localhost:3000 | перекрестное происхождение | разные доменные имена |
http://127.0.0.1:3001 | перекрестное происхождение | разные порты |
Каковы последствия перекрестного происхождения? Есть три обобщения: Cookie, LocalStorage, IndexedDB не могут быть получены; узлы dom не могут быть получены; общая Ajax-связь не может быть выполнена; появление междоменных решений должно решить вышеуказанные болевые точки.
кросс-доменный JSONP
Когда дело доходит до междоменного JSONP, я должен упомянуть об этом в первую очередь.script
этикетки иimg
,iframe
Подобно тегам, эти теги не ограничены политикой одного и того же происхождения.Основой JSONP является выполнение запроса целевого URL-адреса путем динамической загрузки тегов сценария.
Давайте сначала посмотрим на вызов JSONPHeaders
раздел, поля следующие:
Request URL:http://127.0.0.1:3000/?callback=handleResponse
Request Method:GET
Status Code:200 OK
Remote Address:127.0.0.1:3000
можно четко найти вRequest URL
есть предложение?callback=handleResponse
, handleResponse, за которым следует этот обратный вызов, является именем функции обратного вызова (которое может быть взято произвольно), сервер получит этот параметр, а затем объединит его в форму, подобнуюhandleResponse(JSON)
Верните его во внешний интерфейс в виде JSONP == JSON с отступом, как показано на рисунке ниже.В это время браузер автоматически вызовет нашу предопределенную функцию handleResponse.
Пример внешнего кода: (источникhttp://127.0.0.1:3001)
function handleResponse(res) {
console.log(res) // {text: "jsonp"}
}
const script = document.createElement('script')
script.src = 'http://127.0.0.1:3000?callback=handleResponse'
document.head.appendChild(script)
Пример кода на стороне сервера: (Источникhttp://127.0.0.1:3000)
const server = http.createServer((req, res) => {
if (~req.url.indexOf('?callback')) { // 简单处理 JSONP 跨域的时候
const obj = {
"text": 'jsonp',
}
const callback = req.url.split('callback=')[1]
const json = JSON.stringify(obj)
const build = callback + `(${json})`
res.end(build) // 这里返还给前端的是拼接好的 JSON 对象
}
});
Можно видеть, что JSONP имеет преимущество в прямом доступе к тексту ответа, но нелегко подтвердить, не выполняется ли запрос JSONP, потому что событие onerror тега script широко не поддерживается браузерами, и оно может поддерживать только Вызов метода GET.
Перекрестный домен CORS
CORS (Cross-Origin Resource Sharing) можно понимать как расширенную версию Ajax, а также текущее широко распространенное междоменное решение. Его основная идея заключается в前端与后端进行 Ajax 通信时,通过自定义 HTTP 头部设置从而决定请求或响应是否生效
.
Например, интерфейсный код (urlhttp://127.0.0.1:3001) написал сегмент Ajax, код такой:
const xhr = new XMLHttpRequest()
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) {
console.log('responseTesx:' + xhr.responseText)
}
}
}
xhr.open('get', 'http://127.0.0.1:3000', true)
xhr.send()
Из-за несоответствия портов в это время вызываются разные источники, в это время такая строка полей будет найдена в заголовках запроса.
Origin: http://127.0.0.1:3001
И в консоли появится сообщение об ошибке:
Failed to load http://127.0.0.1:3000/: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:3001' is therefore not allowed access.
В это время вам нужно установить поле на стороне сервераAccess-Control-Allow-Origin
, его роль заключается в том, чтобы установить запрос из какого источника разрешен, если установлено значение*
, указывающий, что разрешены запросы из произвольных источников. Пример кода сервера выглядит следующим образом:
http.createServer((req, res) => {
res.setHeader('Access-Control-Allow-Origin', 'http://127.0.0.1:3001') // 设置允许来自 http://127.0.0.1:3001 源的请求
})
CORS делится на простые запросы и непростые запросы. Это можно отличить так, если метод запросаPOST
,GET
,HEAD
это простой запрос, другие методы, такие какPUT
,DELETE
Подождите не простой запрос, если это не простой запрос, вы можете увидеть его еще раз в Сети ChromeRequest Method
дляOPTIONS
запрос. Как показано ниже:
Этот запрос можно назвать предварительным запросом, в переводе на просторечие браузер спрашивает сервер, 'серверный брат, я хочу сделать запрос PUT на этот раз, пожалуйста, пришлите мне пропуск', серверный брат видит, что браузерный брат такой внимательный, что дал ему пропуск под названиемAccess-Control-Allow-Methods:PUT
, и браузер может с радостью выполнять запросы PUT. Пример кода сервера выглядит следующим образом:
http.createServer((req, res) => {
res.setHeader('Access-Control-Allow-Origin', 'http://127.0.0.1:3001')
res.setHeader('Access-Control-Allow-Methods', 'http://127.0.0.1:3001')
})
Поговорив о разнице между простым запросом и непростым запросом, давайте посмотрим, как использовать CORS для реализации междоменной передачи файлов cookie.Во-первых, установите значение файла cookie на сервере и отправьте его в браузер. .Если это не междоменное, то браузер снова при запросе к серверу принесет куки, предоставленные сервером, а как насчет междоменного? Не продавай, нужно поставить на серверAccess-Control-Allow-Credentials
поля и настройки на стороне клиентаwithCredentials
Поле, оба незаменимы, код такой:
Пример внешнего кода: (источникhttp://127.0.0.1:3001)
const xhr = new XMLHttpRequest()
...
xhr.withCredentials = true // 传 cookie 的时候前端要做的
xhr.open('get', 'http://127.0.0.1:3000', true)
xhr.send()
Пример кода на стороне сервера: (источникhttp://127.0.0.1:3000)
const server = http.createServer((req, res) => {
res.setHeader('Access-Control-Allow-Origin', 'http://127.0.0.1:3001') // 必填:接受域的请求
res.setHeader('Set-Cookie', ['type=muyy']) // 下发 cookie
res.setHeader('Access-Control-Allow-Credentials', true) // ② 选填:是否允许浏览器传 cookie 到服务端,只能设置为 true
res.end('date from cors')
})
На данный момент было представлено практическое применение нескольких ключевых HTTP-заголовков в CORS.Для получения более подробной информации см.Cross-Origin Resource Sharing, и, наконец, суммируйте преимущества и недостатки CORS. Преимущество заключается в том, что он поддерживает все типы методов HTTP. Недостатком является то, что некоторые старые браузеры не поддерживают CORS.
hash + iframe
В начале статьи было упомянуто, что тег iframe также является одним из тегов, которые не ограничены политикой одного и того же происхождения.Основная междоменная идея хэш + iframe заключается в динамическом изменении значения хеша. src тега iframe в источнике A, в источнике B переданоwindow.onhashchange
для захвата соответствующего хеш-значения. По идее не сложно перейти сразу к коду:
Пример кода страницы (источникhttp://127.0.0.1:3000)
<body>
<iframe src="http://127.0.0.1:3001"></iframe>
<script>
const iframe = document.getElementsByTagName('iframe')[0]
iframe.setAttribute('style', 'display: none')
const obj = {
data: 'hash'
}
iframe.src = iframe.src + '#' + JSON.stringify(obj) // ① 关键语句
</script>
</body>
Пример кода страницы B (источникhttp://127.0.0.1:3001)
window.onhashchange = function() { // ① 关键语句
console.log('来自 page2 的代码 ' + window.location.hash) // 来自 page2 的代码 #{"data":"hash"}
}
Обновив страницу A, вы можете обнаружить, что следующие поля печатаются на консоли, пока что реализован междоменный доступ.
来自 page2 的代码 #{"data":"hash"}
Преимущество междоменной связи таким образом заключается в том, что она поддерживает связь между страницами, а недостатком является то, что она поддерживает только метод GET и одностороннюю междоменную связь.
postMessage
Чтобы добиться обмена сообщениями между документами (обмена сообщениями между документами), именуемого XDM. HTML5 дает api - postMessage, метод postMessage() получает два параметра:发送消息
так же как消息接收方所在域的字符串
. Пример кода выглядит следующим образом:
Пример кода страницы (источникhttp://127.0.0.1:3000)
<body>
<iframe src="http://127.0.0.1:3001"></iframe>
<script>
const iframe = document.getElementsByTagName('iframe')[0]
iframe.setAttribute('style', 'display: none')
iframe.onload = function() { // 此处要等 iframe 加载完毕,后续代码才会生效
iframe.contentWindow.postMessage('a secret', 'http://127.0.0.1:3001')
}
</script>
</body>
Пример кода страницы B (источникhttp://127.0.0.1:3001)
window.addEventListener('message', function(event) {
console.log('From page1 ' + event.data)
console.log('From page1 ' + event.origin)
}, false)
Обновив страницу A, вы можете обнаружить, что следующие поля печатаются на консоли, пока что реализован междоменный доступ.
From page1 a secret
From page1 http://127.0.0.1:3000
Преимущество этого междоменного метода заключается в том, что он поддерживает двустороннюю связь между страницами и страницами, а недостаток в том, что он может поддерживать только вызовы метода GET.
WebSockets
WebSockets — это протокол HTML5, цель которого — установить полнодуплексную связь через постоянное соединение. Поскольку WebSockets принимает собственный протокол, преимущество заключается в том, что клиент и сервер отправляют меньше данных, а недостатком является то, что требуется дополнительный сервер. Основное использование заключается в следующем:
const ws = new WebSocket('ws://127.0.0.1:3000')
ws.onopen = function() {
// 连接成功建立
}
ws.onmessage = function(event) {
// 处理数据
}
ws.onerror = function() {
// 发生错误时触发,连接中断
}
ws.onclose = function() {
// 连接关闭时触发
}
Конечно, мы обычно используем сторонние библиотеки, которые инкапсулируют WebSockets.socket.io, который здесь не подробно описан.
адрес проекта
Демонстрации пяти междоменных практик, описанных выше, были загружены наcross-domain, интерфейсная среда построена на основе приложения create-react-app, а внутренняя среда построена на основе node.
Конечно, есть и другие способы реализации междоменного метода, и последующая работа постепенно заполнит пробел по мере необходимости~