предисловие
Взаимодействия с внешними и внутренними данными часто сталкиваются с междоменными запросами, что такое междоменные и что такое междоменные методы, я думаю, что я должен записать это.
1. Что такое междоменный домен?
1. Что такое политика единого происхождения и что она ограничивает?
- Политика того же происхождения — это политика безопасности. Так называемая гомология относится к одному и тому же протоколу, доменному имени и порту. Из соображений безопасности браузеры разрешают взаимодействие интерфейсов только под этим доменным именем, а клиентские скрипты из разных источников не могут читать или записывать ресурсы друг друга без явной авторизации.
- Политика того же происхождения ограничивает следующее:
-
Cookie, LocalStorage, IndexedDB и другое содержимое хранилища.
-
DOM-узел
-
После отправки AJAX-запроса другой источник будет перехвачен браузером.
Но есть три тега, которые разрешают загрузку ресурсов из разных источников:<img src=XXX> <link href=XXX> <script src=XXX>
Здесь на помощь приходит JSONP.
2. Распространенные междоменные сценарии
Если какой-либо протокол, имя поддомена, имя основного домена и номер порта отличаются, это считается другим источником.
примечание: В частности, два момента:
- Во-первых: если это междоменная проблема, вызванная протоколами и портами, «внешний интерфейс» бессилен.
- Во-вторых: в междоменной проблеме это определяется только «заголовком URL-адреса», а не на основе того, является ли IP-адрес, соответствующий доменному имени, одинаковым. «Заголовок URL» можно понимать как «протокол, имя домена и порт должны совпадать».
- Третье: Запрос является междоменным, поэтому он отправляется? Кроссдоменность не означает, что запрос нельзя отправить, запрос можно отправить, сервер может принять запрос и вернуть результат нормально, но результат перехватывается браузером
2. Междоменные решения
1. JSONP
1.1 Принцип JSONP
利用<script>标签没有跨域限制的漏洞,网页可以得到从其他来源动态产生的JSON数据。JSONP请求一定需要对方的服务器做支持才可以。
1.2 Сравнение JSONP и AJAXJSONP — это то же самое, что и AJAX, это способ, с помощью которого клиент может отправить запрос на сервер и получить данные с сервера. Но AJAX относится к политике одного и того же происхождения, а JSONP относится к политике другого происхождения (междоменный запрос).
1.3 Преимущества и недостатки JSONPHSONP Advantage - это простота хорошей совместимости, ее можно использовать для решения проблемы основных браузеров с перекрестным доменным доменным доступом. Недостатком является то, что только поддержка метода GET имеет ограничения, небезопасные могут подвергаться приступам XSS.
1.4 Процесс внедрения JSONP
- Объявить функцию обратного вызова, имя функции которой (например, show) используется в качестве значения параметра для передачи на сервер, который запрашивает данные между доменами, а параметр функции должен получать целевые данные (данные, возвращаемые сервером).
- Создайте тег
- После того, как сервер получит запрос, ему необходимо выполнить специальную обработку: объединить переданное имя функции и данные, которые он должен вам предоставить, в строку, например: переданное имя функции — show, а ее подготовленные данные — show( «Я тебя не люблю»).
- Наконец, сервер возвращает подготовленные данные клиенту по протоколу HTTP, а клиент вызывает и выполняет функцию обратного вызова (show), объявленную перед операцией с возвращенными данными.
Теперь давайте сами обернем функцию JSONP
// 封装 JSONP函数
function jsonp({ url, params, callback }) {
return new Promise((resolve, reject) => {
let script = document.createElement('script');
params = JSON.parse(JSON.stringify(params));
let arrs = [];
for (let key in params) {
arrs.push(`${key}=${params[key]}`);
}
arrs.push(`callback=${callback}`);
script.src = `${url}?${arrs.join('&')}`;
document.body.appendChild(script);
window[callback] = function (data) {
resolve(data);
document.body.removeChild(script);
}
})
}
// 前端调用
jsonp({
url: 'http://localhost:3000/say',
params: {
wd: 'I Love you'
},
callback: 'show'
}).then(data => {
console.log(data)
})
// 后端响应
// 这里用到了 express
var express = require('express');
var router = express.Router();
var app = express();
router.get('/say',function(req,res,next) {
//要响应回去的数据
let data = {
username : 'zs',
password : 123456
}
let {wd , callback} = req.query;
console.log(wd);
console.log(callback);
// 调用回调函数 , 并响应
res.end(`${callback}(${JSON.stringify(data)})`);
})
app.use(router);
app.listen(3000);
2. CORS
CORS требует поддержки как браузера, так и серверной части. IE8 и IE9 необходимо реализовать через XDomainRequest
Браузер будет автоматически осуществлять связь CORS, а ключом к реализации связи CORS является серверная часть. Пока серверная часть реализует CORS, реализуется междоменный доступ.
Сервер может установить Access-Control-Allow-Origin для включения CORS. Это свойство указывает, какие доменные имена могут получить доступ к ресурсу. Если установлен подстановочный знак, это означает, что все веб-сайты могут получить доступ к ресурсу.
Хотя настройка CORS не имеет ничего общего с фронтендом, но если решить междоменную проблему таким образом, то при отправке запросов будет две ситуации, а именнопростой запроса такжесложный запрос.
простой запрос
Пока следующие два условия выполняются одновременно, это простой запрос
Условие 1: используйте один из следующих методов:
- GET
- HEAD
- POST
Условие 2Значение :Content-Type ограничено одним из следующих трех:
- text/plain
- multipart/form-data
- приложение / x-www-form-urlencoded XMLHttpRequestUpload любой объектный запрос не регистрируется ни в каких прослушивателях событий;
сложный запрос
Запрос, который не соответствует вышеуказанным условиям, определенно является сложным запросом. Для запросов CORS сложных запросов перед формальным общением будет добавлен запрос HTTP-запроса, который называется предварительным запросом. Этот запрос является методом выбора, и этот запрос используется, чтобы узнать, разрешает ли сервер междоменные запросы. .
Когда мы используем PUT для запроса фона, это сложный запрос, и фон необходимо настроить следующим образом:
// 允许哪个方法访问我
res.setHeader('Access-Control-Allow-Methods', 'PUT')
// 预检的存活时间
res.setHeader('Access-Control-Max-Age', 6)
// OPTIONS请求不做任何处理
if (req.method === 'OPTIONS') {
res.end()
}
// 定义后台返回的内容
app.put('/getData', function(req, res) {
console.log(req.headers)
res.end('我不爱你')
})
Далее давайте рассмотрим пример полного запроса и представим поля, связанные с запросом CORS.
//index.html
// 前端代码
<script>
let xhr = new XMLHttpRequest();
document.cookie = 'name=hw';
xhr.withCredentials = true; //前端设置是否带 cookie
xhr.open('PUT','http://localhost:4000/getData',true);
xhr.setRequestHeader('name','hw');
xhr.onreadystatechange = function() {
if(xhr.readyState === 4) {
if(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) {
console.log(JSON.parse(xhr.response));
console.log(xhr.getResponseHeader('name'))
}
}
}
xhr.send();
</script>
// server1.js
let express = require('express');
let app = express();
app.use(express.static(__dirname))
app.listen(3000)
// 后端代码
let express = require('express')
let app = express()
let whitList = ['http://localhost:3000'] //设置白名单
app.use(function(req, res, next) {
let origin = req.headers.origin
if (whitList.includes(origin)) {
// 设置哪个源可以访问我
res.setHeader('Access-Control-Allow-Origin', origin)
// 允许携带哪个头访问我
res.setHeader('Access-Control-Allow-Headers', 'name')
// 允许哪个方法访问我
res.setHeader('Access-Control-Allow-Methods', 'PUT')
// 允许携带cookie
res.setHeader('Access-Control-Allow-Credentials', true)
// 预检的存活时间
res.setHeader('Access-Control-Max-Age', 6)
// 允许返回的头
res.setHeader('Access-Control-Expose-Headers', 'name')
if (req.method === 'OPTIONS') {
res.end() // OPTIONS请求不做任何处理
}
}
next()
})
app.put('/getData', function(req, res) {
let data = {
username : 'zs',
password : 123456
}
console.log(req.headers)
res.setHeader('name', 'jw') //返回一个响应头,后台需设置
res.end(JSON.stringify(data))
})
app.get('/getData', function(req, res) {
console.log(req.headers)
res.end('he')
})
app.listen(4000)
3. postMessage
postMessage — это API в HTML5 XMLHttRequest Level 2 и один из немногих атрибутов окна для междоменных междоменных операций, его можно использовать для решения следующих проблем:
- Передача данных страницы и новое окно, которое она открывает
- Передача сообщений между несколькими окнами
- Страницы с вложенными сообщениями iframe
- Междоменная передача данных в описанных выше трех сценариях
Метод postMessage() позволяет сценариям из разных источников взаимодействовать асинхронно с ограниченным обменом данными, обеспечивая межтекстовый документ, многооконный и междоменный обмен сообщениями.
API大概是这样的
otherWindow.postMessage(message,targetOrigin,[transfer])
- сообщение: данные для отправки в другие окна
- targetOrigin: укажите, какие окна могут получать события сообщения через свойство origin окна, и его значение может быть строкой "*" (представляющей неограниченное количество). или URL-адрес. При отправке сообщения, если какой-либо протокол, адрес хоста или порт целевого окна не соответствует значению, предоставленному targetOrigin, сообщение не будет отправлено; сообщение будет отправлено только в том случае, если три точно совпадают.
- transfer (необязательно): это строка объектов Transferable, которые передаются вместе с сообщением. Право собственности на эти объекты будет передано получателю сообщения, а отправитель больше не сохранит право собственности.
Ниже, давайте используем пример, чтобы проиллюстрировать любое использование
4. websocket
Протокол WebSocket по сути является протоколом на основе TCP.
Чтобы установить соединение WebSocket, клиентский браузер должен сначала инициировать HTTP-запрос к серверу.Этот запрос отличается от обычного HTTP-запроса и содержит некоторую дополнительную информацию заголовка, среди которых дополнительная информация заголовка"Upgrade:WebSocket"Указывает, что это HTTP-запрос на обновление протокола.Сервер анализирует дополнительную информацию заголовка, а затем генерирует ответное сообщение и возвращает его клиенту.Соединение WebSocket между клиентом и сервером устанавливается, и обе стороны могут свободно передавать через этот канал соединения, и соединение будет сохраняться до тех пор, пока одна из сторон клиента или сервера активно не закроет соединение.
Нативный WebSocket API не очень удобен в использовании, мы используем Socket.io, который хорошо инкапсулирует интерфейс webSocket, предоставляет более простой и гибкий интерфейс, а также обеспечивает обратную совместимость для браузеров, не поддерживающих webSocket.
Давайте посмотрим на другой пример:
//前端
<script>
// 定义数据
let Data = {
username : 'hw',
password : 456789
}
let socket = new WebSocket('ws://localhost:4000');
socket.onopen = function() {
socket.send(JSON.stringify(Data)); // 向服务器发送数据
}
socket.onmessage = function(e) {
console.log(JSON.parse(e.data)); // 接收服务器返回的数据
}
</script>
// 后端
let express = require('express');
let app = express();
let WebSocket = require('ws');
let wss =new WebSocket.Server({port:4000})
// 定义数据
let Data = {
username : 'zs',
password : 123456
}
wss.on('connection', function(ws) {
ws.on('message',function(data) {
console.log(JSON.parse(data))
ws.send(JSON.stringify(Data))
})
})
5. Прокси промежуточного программного обеспечения узла (дважды междоменный)
Принцип реализации: **Политика того же происхождения — это стандарт, которому должны следовать браузеры, и если это межсерверный запрос, ему не нужно следовать политике того же происхождения. **Прокси-сервер, необходимо выполнить следующие действия:
- Принимать запросы клиентов
- отправить запрос на сервер
- Получить данные ответа сервера
- отправить ответ клиенту
//前端
<script>
function ajax(
{
url = '',
method = 'get',
headers = {},
data = ''
}
) {
return new Promise((resolve,reject) => {
// 兼容性处理
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if(xhr.readyState === 4) {
if((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
try {
// 获取数据
var response = JSON.parse(xhr.responseText);
resolve(response);
} catch( e ) {
reject(e);
}
} else {
reject(new Error('Request was unsuccessful' + xhr.statusText));
}
}
}
xhr.open(method,url,true);
// 设置头部
for(let key in headers) {
xhr.setRequestHeader(key,headers[key]);
}
xhr.send(JSON.stringify(data))
})
}
ajax({
url : 'http://localhost:3000',
method : 'post',
headers : {
'Content-Type':'application/json;charset=utf-8'
},
data : {
username : 'hw',
password : '789'
}
})
.then((value,code)=>{
console.log(value)
})
.catch(err=>{
console.log(err)
})
</script>
// 代理服务器(http://localhost:3000)
const http = require('http');
// 第一步 : 接受客户端请求
const server = http.createServer((request, response) => {
// 代理服务器,直接和浏览器直接交互,需要设置CORS的首部字段
response.writeHead(200, {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': '*',
'Access-Control-Allow-Headers': 'Content-Type'
})
if(request.method === 'options') {
response.end();
}
// 第二步 : 将请求转发给服务器
const proxyRequest = http
.request(
{
host: '127.0.0.1',
port: 4000,
url: '/',
method: request.method,
headers: request.headers,
},
serverResponse => {
// 第三步:收到服务器的响应
var body = ''
serverResponse.on('data', chunk => {
body += chunk
})
serverResponse.on('end', () => {
console.log('The data is ' + body)
// 第四步:将响应结果转发给浏览器
response.end(body)
})
}
)
.end()
})
server.listen(3000, ()=>{
console.log('The proxyServer is running at http://localhost:3000')
})
//后端服务器
// http://localhost:4000
const http = require('http');
const data = { title : 'zs', password : '123'};
const server = http.createServer((request,response) => {
if(request.url === '/') {
response.end(JSON.stringify(data))
}
})
server.listen(4000,'127.0.0.1',()=> {
console.log('The server is running at http://127.0.0.1:4000')
})
обратный прокси nginx
предисловие
Честно говоря, знакомство с nginx занимает некоторое время, здесь я расскажу, как использовать nginx для междоменного взаимодействия.
я не очень хорош в этом
nginx с node.js
'Nginx是一款轻量级的HTTP服务器,采用事件驱动的异步非阻塞处理方式框架,这让其具有极好的IO性能,时常用于服务端的反向代理与负载均衡'
Это кажется очень похожим на node.js, но на самом деле все они имеют свои области знаний: Nginx лучше обрабатывает базовые ресурсы на стороне сервера (обработка и пересылка статических ресурсов, обратный прокси-сервер, балансировка нагрузки и т. д.). , node.js лучше подходит для обработки специфической бизнес-логики верхнего уровня. Их можно комбинировать, чтобы помочь фронтенд-разработке.
прокси-сервер
Что такое обратный прокси Интернет-приложения в основном основаны на базовой структуре CS, то есть на стороне клиента и на стороне сервера. Прокси — это на самом деле сервер, который предоставляет конкретную услугу между клиентской стороной и реальной серверной стороной, то есть прокси-сервером.
прямой прокси
прямой проксиЯ уверен, что вы использовали, на самом деле, инструменты обхода на самом деле инструмент прямого прокси. Он будет получать доступ к запросам сервера стены веб-браузера, агенты могут получить доступ к сайту на прокси-сервере прокси-сервера, прокси-сервере для прокси-контента на сервере для получения стены сервера, а затем передается клиенту.
Конкретный процесс выглядит следующим образом:
обратный прокси
Обратный прокси-сервер противоположен прямому прокси-серверу, сначала посмотрите на блок-схему:
В обратном прокси (на самом деле это происходит со всеми запросами больших страниц веб-сайта) клиент отправляет запрос, который хочет получить доступ к контенту на сервере. Но он будет отправлен на прокси-сервер proxy, который будет проксировать запрос на внутренние серверы, принадлежащие к той же LAN, что и он сам, и на этих внутренних серверах хранится тот контент, который пользователь действительно хочет получить.
Это означает, что внешним клиентам предоставляется единая запись прокси.Запрос клиента сначала проходит через прокси-сервер.Что касается того, к какому контенту сервера фактически осуществляется доступ в интрасети, то прокси-сервер контролирует его.
В двух словах: к прокси-серверу и реальному серверу-серверу можно получить доступ напрямую, и они относятся к локальной сети (серверной интрасети); прокси прозрачен для пользователя, то есть незаметен.
Почему обратный прокси nginx
причина:
- Безопасность и разрешения. Видно, что после использования обратного прокси-сервера клиент не сможет получить прямой доступ к серверу реального контента через запрос, а должен сначала пройти через nginx.Опасный или неавторизованный контент запроса может быть отфильтрован на уровне nginx, чтобы гарантировать Безопасность сервера.
- Балансировка нагрузки. Например, контент веб-сайта размещен на нескольких серверах, эти машины можно рассматривать как кластер, тогда nginx может «равномерно» распределять полученные клиентские запросы на все серверы в кластере (внутренний модуль обеспечивает разнообразную нагрузку алгоритмы балансировки) для достижения балансировки нагрузки сервера. Кроме того, в nginx также есть функция проверки работоспособности (проверка сердцебиения сервера), которая будет периодически опрашивать и отправлять запросы проверки работоспособности на все серверы в кластере, чтобы проверить, не находятся ли какие-либо серверы в кластере в ненормальном состоянии. клиентские запросы, поступающие от прокси-сервера, не будут отправляться на сервер (при последующей проверке работоспособности выясняется, что сервер вернулся в нормальное состояние), что обеспечивает стабильность клиентского доступа.
Скачиваем и устанавливаем nginx под windows
скачать nginx
конфигурация nginx
Небольшая функция nginx
1. Быстро реализовать простой контроль доступа
Часто возникает ситуация, когда вы хотите разрешить некоторым определенным группам пользователей (например, интрасети компании) доступ или управлять определенным URL-адресом из доступа.
nginx的配置如下:
location / {
deny 192.168.1.100; // 禁止
allow 192.168.1.10/200; // 允许
allow 10.110.50.16;
deny all; // 禁止所有
}
Фактически запрещать и разрешать - это синтаксис в модуле ngx_http_access_module (уже встроенном).
Метод сопоставления применяется сверху вниз, и сопоставление выскочит и больше не будет совпадать.
Например, приведенная выше конфигурация означает сначала запретить доступ к 192.168.1.100, затем разрешить доступ в пределах IP-сегмента 192.168.1.10-200 (за исключением 192.168.1.100) и разрешить доступ к одному IP-адресу 10.110.50.16, не оставляя совпадений. Любой доступ запрещен.
2. Решите междоменный
Во многих отношениях для решения междоменных задач необходима поддержка сервера, использование Nginx может решить проблему междоменных запросов в чистом интерфейсе.
Конфигурация nginx выглядит следующим образом:
server
{
listen 3002;
server_name localhost;
location /ok {
proxy_pass http://localhost:3000;
# 指定允许跨域的方法,*代表所有
add_header Access-Control-Allow-Methods *;
# 预检命令的缓存,如果不缓存每次会发送两次请求
add_header Access-Control-Max-Age 3600;
# 带cookie请求需要加上这个字段,并设置为true
add_header Access-Control-Allow-Credentials true;
# 表示允许这个域跨域调用(客户端发送请求的域名和端口)
# $http_origin动态获取请求客户端请求的域 不用*的原因是带cookie的请求不支持*号
add_header Access-Control-Allow-Origin $http_origin;
# 表示请求头的字段 动态获取
add_header Access-Control-Allow-Headers
$http_access_control_request_headers;
# OPTIONS预检命令,预检命令通过时才发送请求
# 检查请求的类型是不是预检命令
if ($request_method = OPTIONS){
return 200;
}
}
}
использованная литература
Девять способов реализации междоменных запросов
nginx и фронтенд разработка
Суммировать
- CORS поддерживает все типы HTTP-запросов и является основным решением для междоменных HTTP-запросов.
- JSONP поддерживает только запросы GET. Преимущество JSONP в том, что он поддерживает старые браузеры и может запрашивать данные с веб-сайтов, которые не поддерживают CORS.
- Будь то прокси промежуточного слоя Node или обратный прокси nginx, сервер не ограничен политикой одного и того же источника.
- В повседневной работе чаще всего используются междоменные решения — cors и обратные прокси nginx.
наконец
Ну, в конце концов, я признаю, что возился с nginx.
Этому nginx научился у меня несколько дней, но я так и не понял, как это сделать.
Привет, добавлю позже.