9 tipos de método de dominios cruzados para resolver el problema del navegador

¿Qué es la cruz-dominio?

Entre dominios significa que el navegador no puede ejecutar scripts de otros sitios. Se compone de los mismos navegadores de política origen causados a las restricciones de seguridad del navegador para la implementación de JavaScript.

Aquí explicar, no es el navegador entre dominios por razones de seguridad del usuario, si no escriben el mismo navegador política de origen, no es necesario considerar un problema de varios dominios. pote del navegador, a la derecha.

restricciones de la política origen de un comportamiento poco:

Galleta, LocalStorage y no se puede leer IndexDB

JS objetos DOM y no pueden conseguir

Ajax solicitud no se apaga

Dicho claramente, es que utilizamos AJAX para enviar una solicitud asincrónica en el extremo anterior, si la dirección URL de esta solicitud a la dirección URL de la barra de direcciones del protocolo actual es diferente en diferentes nombres de dominio, no un puerto al mismo tiempo, se han convertido en varios dominios,

Aquí Insertar imagen Descripción

Después de la aparición de problemas de varios dominios, el error siguiente en la consola:

Aquí Insertar imagen Descripción

A continuación, unas cuantas castañas entre dominios:

URL explicación Ya sea para permitir la comunicación
http://www.demo.com/a.js
http://www.demo.com/b.js
http://www.demo.com/lab/c.js
El mismo nombre de dominio o una ruta de archivo diferente permitir
http://www.demo.com:8000/a.js
http://www.demo.com/b.js
El mismo nombre de dominio, un puerto diferente no se permite
http://www.demo.com/a.js
https://www.demo.com/b.js
El mismo nombre de dominio, protocolos diferentes no se permite
http://www.demo.com/a.js
http://127.0.0.1/b.js
Y los nombres de dominio corresponden a la misma ip no se permite
http://www.demo.com/a.js
http://x.demo.com/b.js
http://demo.com/c.js
dominio principal misma, de subdominios no se permite
http://www.demo1.com/a.js
http://www.demo2.com/b.js
dominio diferente no se permite

soluciones entre dominios

  1. Por jsonp entre dominios
  2. document.domain + iframe multidominio
  3. location.hash + iframe
  4. window.name + iframe multidominio
  5. postMessage entre dominios
  6. Origen cruzado de intercambio de recursos (CORS)
  7. nginx proxy de multidominio
  8. nodejs agente middleware a través de dominios
  9. protocolo WebSocket a través de dominios

En primer lugar, la cruz-dominio jsonp

Por lo general, con el fin de reducir la carga en el servidor web, tenemos que js separadas, css, img y otros recursos estáticos a otro servidor de nombres de dominio independiente, y luego cargar los recursos estáticos de un dominio diferente en páginas html por las respectivas etiquetas son el navegador permitir que, en base a este principio, podemos crear un guión dinámico, y luego solicitar una URL con parámetros para lograr la comunicación entre dominios.

1) aplicación nativa:

 <script>
    var script = document.createElement('script');
    script.type = 'text/javascript';

    // 传参并指定回调执行函数为onBack
    script.src = 'http://www.demo2.com:8080/login?user=admin&callback=onBack';
    document.head.appendChild(script);

    // 回调执行函数
    function onBack(res) {
        alert(JSON.stringify(res));
    }
 </script>

El servidor devuelve el siguiente (es decir, el retorno a realizar una función global):

onBack({"status": true, "user": "admin"})

2) ajax jquery:

$.ajax({
    url: 'http://www.demo2.com:8080/login',
    type: 'get',
    dataType: 'jsonp',  // 请求方式为jsonp
    jsonpCallback: "onBack",    // 自定义回调函数名
    data: {}
});

3) vue.js:

this.$http.jsonp('http://www.demo2.com:8080/login', {
    params: {},
    jsonp: 'onBack'
}).then((res) => {
    console.log(res); 
})

Node.js trasera Ejemplo de código:

var querystring = require('querystring');
var http = require('http');
var server = http.createServer();

server.on('request', function(req, res) {
    var params = qs.parse(req.url.split('?')[1]);
    var fn = params.callback;

    // jsonp返回设置
    res.writeHead(200, { 'Content-Type': 'text/javascript' });
    res.write(fn + '(' + JSON.stringify(params) + ')');

    res.end();
});

server.listen('8080');
console.log('Server is running at port 8080...');

jsonp inconveniente: Sólo se puede obtener un tipo de solicitud de realización.

Dos, document.domain + iframe multidominio

Sólo esta realización mismo que el dominio primario, subdominios del escenario entre dominios.

El principio: dos páginas se ajustan forzosamente por document.domain principal de dominio basados ​​en JS, para lograr el mismo dominio.

1) la ventana padre ( http://www.demo.com/a.html) )

<iframe id="iframe" src="http://child.demo.com/b.html"></iframe>
<script>
    document.domain = 'demo.com';
    var user = 'admin';
</script>

ventana secundaria :( http://child.demo.com/b.html) )

<script>
    document.domain = 'demo.com';
    // 获取父窗口中变量
    alert('get js data from parent ---> ' + window.parent.user);
</script>

Tres, location.hash + iframe entre dominios

El principio: a y b sean de comunicación entre dominios entre sí, una página intermedia se consigue por c. Tres páginas, el valor con el iframe location.hash pase entre dominios, JS acceso directo a la comunicación entre el mismo dominio.

implementación específica: un dominio: a.html -> B Dominio: b.html -> un dominio: c.html, a y b son diferentes dominios pueden comunicarse a través de una sola vía valor hash, B y C son diferentes sólo un único dominio a la comunicación, pero con un mismo dominio C, C de modo que una página se puede acceder por todos los objetos parent.parent.

El principio: a y b sean de comunicación entre dominios entre sí, una página intermedia se consigue por c. Tres páginas, el valor con el iframe location.hash pase entre dominios, JS acceso directo a la comunicación entre el mismo dominio.

implementación específica: un dominio: a.html -> B Dominio: b.html -> un dominio: c.html, a y b son diferentes dominios pueden comunicarse a través de una sola vía valor hash, B y C son diferentes sólo un único dominio a la comunicación, pero con un mismo dominio C, C de modo que una página se puede acceder por todos los objetos parent.parent.

1) a.html :( http://www.demo1.com/a.html) )

<iframe id="iframe" src="http://www.demo2.com/b.html" style="display:none;"></iframe>
<script>
    var iframe = document.getElementById('iframe');

    // 向b.html传hash值
    setTimeout(function() {
        iframe.src = iframe.src + '#user=admin';
    }, 1000);
    
    // 开放给同域c.html的回调方法
    function onCallback(res) {
        alert('data from c.html ---> ' + res);
    }
</script>

2) b.html :( http://www.demo2.com/b.html) )

<iframe id="iframe" src="http://www.demo1.com/c.html" style="display:none;"></iframe>
<script>
    var iframe = document.getElementById('iframe');

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

3) c.html :( http://www.demo1.com/c.html) )

<script>
    // 监听b.html传来的hash值
    window.onhashchange = function () {
        // 再通过操作同域a.html的js回调,将结果传回
        window.parent.parent.onCallback('hello: ' + location.hash.replace('#user=', ''));
    };
</script>

Cuatro, window.name + iframe multidominio

Window.name atributos únicos: el valor del nombre todavía existe en las diferentes páginas (o incluso dominio diferente) se carga, y puede soportar valor de nombre muy largo (2 MB).

1) a.html :( http://www.demo1.com/a.html) )

var proxy = function(url, callback) {
    var state = 0;
    var iframe = document.createElement('iframe');

    // 加载跨域页面
    iframe.src = url;

    // onload事件会触发2次,第1次加载跨域页,并留存数据于window.name
    iframe.onload = function() {
        if (state === 1) {
            // 第2次onload(同域proxy页)成功后,读取同域window.name中数据
            callback(iframe.contentWindow.name);
            destoryFrame();

        } else if (state === 0) {
            // 第1次onload(跨域页)成功后,切换到同域代理页面
            iframe.contentWindow.location = 'http://www.demo1.com/proxy.html';
            state = 1;
        }
    };

    document.body.appendChild(iframe);

    // 获取数据以后销毁这个iframe,释放内存;这也保证了安全(不被其他域frame js访问)
    function destoryFrame() {
        iframe.contentWindow.document.write('');
        iframe.contentWindow.close();
        document.body.removeChild(iframe);
    }
};

// 请求跨域b页面数据
proxy('http://www.demo2.com/b.html', function(data){
    alert(data);
});

2) proxy.html :( http: //www.demo1.com/proxy ... )
la página proxy intermedio, y a.html el mismo campo, el contenido está en blanco.

3) b.html :( http://www.demo2.com/b.html) )

<script>
    window.name = 'This is demo2 data!';
</script>

Resumen: dirección por el dominio local por el atributo iframe src de un conjunto de datos entre dominios que se transmite desde el window.name iframe fuera del dominio para el dominio local. Esta derivación se anticipa al de dominios cruzados acceso a las limitaciones del navegador, pero es seguro para operar.

Cinco, postMessage entre dominios

postMessage HTML5 XMLHttpRequest Nivel 2 se encuentra en la API, y es una de las pocas propiedades ventana puede ser operaciones entre dominios, que pueden ser utilizados para tratar los siguientes aspectos:
A) la página de datos y para abrir la nueva ventana se transmite
b) una ventana mensajería entre
c) y anidada página iframe mensajería
de transferencia de datos d) de lo anterior tres escenarios multidominio

Uso: método postMessage (datos, el origen) toma dos parámetros
de datos: soportes especificación de HTML 5 sustancialmente cualquier tipo o copiar un objeto, pero sólo algunos navegadores soporta una cadena, cuando lo mejor es utilizar los parámetros de transmisión JSON.stringify () de la secuencia .
origen: Protocolo, host, el número de puerto, se puede establecer en "*" representa cualquier ventana a pasar, si desea especificar la ventana actual y luego homóloga a "/".

1) a.html :( http://www.demo1.com/a.html) )

<iframe id="iframe" src="http://www.demo2.com/b.html" style="display:none;"></iframe>
<script>       
    var iframe = document.getElementById('iframe');
    iframe.onload = function() {
        var data = {
            name: 'aym'
        };
        // 向domain2传送跨域数据
        iframe.contentWindow.postMessage(JSON.stringify(data), 'http://www.demo2.com');
    };

    // 接受domain2返回数据
    window.addEventListener('message', function(e) {
        alert('data from demo2 ---> ' + e.data);
    }, false);
</script>

2) b.html :( http://www.demo2.com/b.html) )

<script>
    // 接收domain1的数据
    window.addEventListener('message', function(e) {
        alert('data from demo1 ---> ' + e.data);

        var data = JSON.parse(e.data);
        if (data) {
            data.number = 16;

            // 处理后再发回domain1
            window.parent.postMessage(JSON.stringify(data), 'http://www.demo1.com');
        }
    }, false);
</script>

Seis de origen cruzado de intercambio de recursos (CORS)

solicitudes entre dominios ordinarios: sólo el servidor de configuración de Access-Control-Allow-El origen puede ser, no hay necesidad de ajustar la parte delantera, con una solicitud de galletas para: el extremos delantero y trasero deben ser conjunto.

Tenga en cuenta que: Debido a las limitaciones de la política del mismo origen, la galleta de lectura para varios dominios pide al interfaz de dominio, en lugar de la página actual. Si se quiere lograr la galleta por escrito a la página actual, se puede ver a continuación: Siete, nginx revertir la configuración del proxy proxy_cookie_domain y VIII, nodejs middleware parámetros establecidos agente cookieDomainRewrite.

Actualmente, todos los navegadores soportan esta característica (IE8 +: IE8 / 9 XDomainRequest necesidad de usar objetos para apoyar CORS)), CORS se ha convertido en la corriente principal de las soluciones de varios dominios.

1, el extremo frontal:

1) ajax nativa

// 前端设置是否带cookie
xhr.withCredentials = true;

Código de ejemplo:

var xhr = new XMLHttpRequest(); // IE8/9需用window.XDomainRequest兼容

// 前端设置是否带cookie
xhr.withCredentials = true;

xhr.open('post', 'http://www.demo2.com:8080/login', true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send('user=admin');

xhr.onreadystatechange = function() {
    if (xhr.readyState == 4 && xhr.status == 200) {
        alert(xhr.responseText);
    }
};

2) jQuery ajax

$.ajax({
    ...
   xhrFields: {
       withCredentials: true    // 前端设置是否带cookie
   },
   crossDomain: true,   // 会让请求头中包含跨域的额外信息,但不会含cookie
    ...
});

3) marco vue
añadiendo el siguiente código ajax montaje vue-recurso encapsulado:

Vue.http.options.credentials = true

2, la configuración del servidor:

Si el back-end configurado, el navegador de la consola frontal no aparece no entre dominios mensaje de error, por el contrario, no muestra el éxito conjunto.

1) Fondo de PHP:

response.setHeader("Access-Control-Allow-Origin", "http://www.domain1.com");  // 若有端口需写全(协议+域名+端口)
response.setHeader("Access-Control-Allow-Credentials", "true");

2) Antecedentes nodejs Ejemplo:

ar http = require('http');
var server = http.createServer();
var qs = require('querystring');

server.on('request', function(req, res) {
    var postData = '';

    // 数据块接收中
    req.addListener('data', function(chunk) {
        postData += chunk;
    });

    // 数据接收完毕
    req.addListener('end', function() {
        postData = qs.parse(postData);

        // 跨域后台设置
        res.writeHead(200, {
            'Access-Control-Allow-Credentials': 'true',     // 后端允许发送Cookie
            'Access-Control-Allow-Origin': 'http://www.demo1.com',    // 允许访问的域(协议+域名+端口)
            'Set-Cookie': 'l=a123456;Path=/;Domain=www.demo2.com;HttpOnly'   // HttpOnly:脚本无法读取cookie
        });

        res.write(JSON.stringify(postData));
        res.end();
    });
});

server.listen('8080');
console.log('Server is running at port 8080...');

Siete, nodejs middleware proxy de varios dominios

Middleware agente de nodo de dominios cruzados, nginx sustancialmente el mismo principio, es abierta a través de un servidor proxy, para darse cuenta de los datos de reenvío, modificación de la cabecera de respuesta puede ser una cookie cookieDomainRewrite dominio mediante el establecimiento de parámetros, y escribe una cookie del dominio actual, para facilitar interfaz de autenticación de inicio de sesión.

1, el marco vue no multidominio (cross-dominio 2)

Uso nodo + + expresan conjunto http-proxy-middleware de un servidor proxy.

1) frontal ejemplo de código final:

var xhr = new XMLHttpRequest();

// 前端开关:浏览器是否读写cookie
xhr.withCredentials = true;

// 访问http-proxy-middleware代理服务器
xhr.open('get', 'http://www.demo1.com:3000/login?user=admin', true);
xhr.send();

2) El servidor de middleware:

var express = require('express');
var proxy = require('http-proxy-middleware');
var app = express();

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

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

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

app.listen(3000);
console.log('Proxy server is listen at port 3000...');

3) fondo nodejs

ar http = require('http');
var server = http.createServer();
var qs = require('querystring');

server.on('request', function(req, res) {
    var params = qs.parse(req.url.substring(2));

    // 向前台写cookie
    res.writeHead(200, {
        'Set-Cookie': 'l=a123456;Path=/;Domain=www.demo2.com;HttpOnly'   // HttpOnly:脚本无法读取
    });

    res.write(JSON.stringify(params));
    res.end();
});

server.listen('8080');
console.log('Server is running at port 8080...');

2, vue marco multidominio (cross-dominio 1)

Usando la interfaz de proxy nodo + webpack + webpack-dev-servidor entre dominios. En el entorno de desarrollo, ya que los servicios de representación y de agencias de vue interfaces de webpack-dev-servidor son los mismos, por lo que no entre dominios entre las páginas y la interfaz de proxy, sin necesidad de establecer cabeceras de información entre dominios.

webpack.config.js parte de la configuración:

module.exports = {
    entry: {},
    module: {},
    ...
    devServer: {
        historyApiFallback: true,
        proxy: [{
            context: '/login',
            target: 'http://www.demo2.com:8080',  // 代理跨域目标接口
            changeOrigin: true,
            secure: false,  // 当代理某些https服务报错时用
            cookieDomainRewrite: 'www.demo1.com'  // 可以为false,表示不修改
        }],
        noInfo: true
    }
}

Ocho, protocolo WebSocket a través de dominios

protocolo HTML5 WebSocket es un nuevo protocolo. Implementa el navegador y el servidor de comunicaciones full-duplex, al tiempo que permite las comunicaciones entre dominios, una tecnología de servidor push bien implementado.
Nativo API WebSocket inconveniente para su uso, utilizamos Socket.io, que resume muy bien WebSocket interfaz que proporciona una manera más simple, interfaz flexible, tampoco admite navegador WebSocket ofrece compatibilidad hacia atrás.

1) código front-end:

<div>user input:<input type="text"></div>
<script src="./socket.io.js"></script>
<script>
var socket = io('http://www.demo2.com:8080');

// 连接成功处理
socket.on('connect', function() {
    // 监听服务端消息
    socket.on('message', function(msg) {
        console.log('data from server: ---> ' + msg); 
    });

    // 监听服务端关闭
    socket.on('disconnect', function() { 
        console.log('Server socket has closed.'); 
    });
});

document.getElementsByTagName('input')[0].onblur = function() {
    socket.send(this.value);
};
</script>

2) de fondo socket nodejs:

// 启http服务
var server = http.createServer(function(req, res) {
    res.writeHead(200, {
        'Content-type': 'text/html'
    });
    res.end();
});

server.listen('8080');
console.log('Server is running at port 8080...');

// 监听socket连接
socket.listen(server).on('connection', function(client) {
    // 接收信息
    client.on('message', function(msg) {
        client.send('hello:' + msg);
        console.log('data from client: ---> ' + msg);
    });

    // 断开处理
    client.on('disconnect', function() {
        console.log('Client socket has closed.'); 
    });
});

Nueve, nginx proxy de multidominio

1, la configuración nginx para resolver iconfont entre dominios

js navegador entre dominios de acceso, css, img y otros recursos estáticos convencionales permiten política del mismo origen, pero archivo de fuentes iconfont (EOT | .otf | ttf | woff | SVG) excepción, entonces usted puede agregar la siguiente configuración del servidor nginx recurso estático .

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

2, nginx revertir las interfaces de proxy a través de dominios

principio entre dominios: política del mismo origen es parte de la política de seguridad del navegador, no el protocolo HTTP. HTTP interfaz de llamada del lado del servidor es sólo con el protocolo HTTP, no realiza JS guión, sin política de origen no existe en todo un problema.

Realización de las ideas: la configuración de nginx través de un proxy (el mismo nombre de dominio demo1, diferentes puertos) máquina de trampolín servidor, revertir las interfaces de acceso Demo2 de proxy, y puede modificar la forma en que la información de demostración de cookies para facilitar la cookie de dominio actual escritura de acceso entre dominios.

configuración específica nginx:

#proxy服务器
server {
    listen       81;
    server_name  www.demo1.com;

    location / {
        proxy_pass   http://www.demo2.com:8080;  #反向代理
        proxy_cookie_demo www.demo2.com www.demo1.com; #修改cookie里域名
        index  index.html index.htm;

        # 当用webpack-dev-server等中间件代理接口访问nignx时,此时无浏览器参与,故没有同源限制,下面的跨域配置可不启用
        add_header Access-Control-Allow-Origin http://www.demo1.com;  #当前端只跨域不带cookie时,可为*
        add_header Access-Control-Allow-Credentials true;
    }
}

1) frontal ejemplo de código final:

var xhr = new XMLHttpRequest();

// 前端开关:浏览器是否读写cookie
xhr.withCredentials = true;

// 访问nginx中的代理服务器
xhr.open('get', 'http://www.demo1.com:81/?user=admin', true);
xhr.send();

2) Antecedentes nodejs Ejemplo:

var http = require('http');
var server = http.createServer();
var qs = require('querystring');

server.on('request', function(req, res) {
    var params = qs.parse(req.url.substring(2));

    // 向前台写cookie
    res.writeHead(200, {
        'Set-Cookie': 'l=a123456;Path=/;Domain=www.demo2.com;HttpOnly'   // HttpOnly:脚本无法读取
    });

    res.write(JSON.stringify(params));
    res.end();
});

server.listen('8080');
console.log('Server is running at port 8080...');

Aquí Insertar imagen Descripción

Publicados 124 artículos originales · ganado elogios 9 · Vistas a 20000 +

Supongo que te gusta

Origin blog.csdn.net/p445098355/article/details/105220112
Recomendado
Clasificación