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