跨域总结

1.什么是跨域

同源策略限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的重要安全机制。同源指:协议、域名、端口号必须一致。

同源策略控制了不同源之间的交互,例如在使用XMLHttpRequest 或 标签时则会受到同源策略的约束。这些交互通常分为三类:

  • 通常允许跨域写操作(Cross-origin writes)。例如链接(links),重定向以及表单提交。特定少数的HTTP请求需要添加 preflight。
  • 通常允许跨域资源嵌入(Cross-origin embedding)。
  • 通常不允许跨域读操作(Cross-origin reads)。但常可以通过内嵌资源来巧妙的进行读取访问。例如可以读取嵌入图片的高度和宽度,调用内嵌脚本的方法,或availability of an embedded resource.

下面为允许跨域资源嵌入的示例,即一些不受同源策略影响的标签示例:

  • 标签嵌入跨域脚本。语法错误信息只能在同源脚本中捕捉到。
  • 标签嵌入CSS。由于CSS的松散的语法规则,CSS的跨域需要一个设置正确的Content-Type 消息头。不同浏览器有不同的限制: IE, Firefox, Chrome, Safari (跳至CVE-2010-0051)部分 和 Opera。
  • 嵌入图片。支持的图片格式包括PNG,JPEG,GIF,BMP,SVG,...
  • , 的插件。
  • @font-face 引入的字体。一些浏览器允许跨域字体( cross-origin fonts),一些需要同源字体(same-origin fonts)。
  • // b.html
    

    window.name

    页面可能会因某些限制而改变他的源。脚本可以将 document.domain 的值设置为其当前域或其当前域的超级域。如果将其设置为其当前域的超级域,则较短的域将用于后续源检查。

    a和b是同域的http://localhost:3000, c是独立的http://localhost:4000。
    a通过iframe引入c,c把值放到window.name,再把它的src指向和a同域的b,然后在iframe所在的窗口中即可取出name的值。

    // a.html
    
    
    // c.html
    
    //server.js
    let express = require('express')
    let app = express();
    app.use(express.static(__dirname));
    app.listen(4000);

    location.hash

    window.location 只读属性,返回一个 Location对象,其中包含有关文档当前位置的信息。 window.location : 所有字母必须小写!只要赋给 location 对象一个新值,文档就会使用新的 URL 加载,就好像使用修改后的 URL 调用了 window.location.assign() 一样。需要注意的是,安全设置,如 CORS(跨域资源共享),可能会限制实际加载新页面。

    案例:a、b同域,c单独一个域。a现在想访问c:a通过iframe给c传一个hash值,c收到hash值后再创建一个iframe把值通过hash传递给b,b将hash结果放到a的hash值中。

    // a.html
    
    
    
    // c.html
    //接收a传来的hash值
    console.log(location.hash)
    //创建一个iframe,把回复的消息传给b
    let iframe = document.createElement('iframe');
    iframe.src='http://localhost:3000/b.html#idontloveyou';
    document.body.appendChild(iframe);
    //b.html
    

    window.domain

    window.domain:获取/设置当前文档的原始域部分。
    案例:解决一级域与二级域之间通信。 模拟时需要创建两个不同域的域名用来测试,打开C:WindowsSystem32driversetc 该路径下找到 hosts 文件,在最下面创建一个一级域名和一个二级域名。改为:
    127.0.0.1   www.haoxl.com
    127.0.0.1   test.haoxl.com
    预设a.html = http://www.haoxl.com,
    b.html = http://test.haoxl.com
    // a.html
    
    
    // b.html
    document.domain = 'haoxl.com'
    var a = 'hello world'

    websocket

    WebSocket对象提供了用于创建和管理 WebSocket 连接,以及可以通过该连接发送和接收数据的 API。它是基于TCP的全双工通信,即服务端和客户端可以双向进行通讯,并且允许跨域通讯。基本协议有 ws://(非加密)和 wss://(加密)
    //socket.html
    let socket = new WebSocket('ws://localhost:3000');
    // 给服务器发消息
    socket.onopen = function() {
        socket.send('hello server')
    }
    // 接收服务器回复的消息
    socket.onmessage = function(e) {
        console.log(e.data)
    }
    
    // server.js
    let express = require('express');
    let app = express();
    let WebSocket = require('ws');//npm i ws
    // 设置服务器域为3000端口
    let wss = new WebSocket.Server({port:3000});
    //连接
    wss.on('connection', function(ws){
        // 接收客户端传来的消息
        ws.on('message', function(data){
            console.log(data);
            // 服务端回复消息
            ws.send('hello client')
        })
    })

    Nginx

    Nginx (engine x) 是一个高性能的 HTTP和 反向代理服务器,也是一个 IMAP/POP3/SMTP服务器。

    案例:在nginx根目录下创建json/a.json,里面随便放些内容

    // client.html
    let xhr = new XMLHttpRequest;
    xhr.open('get', 'http://localhost/a.json', true);
    xhr.onreadystatechange = function() {
        if(xhr.readyState === 4){
            if(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304 ){
                console.log(xhr.response);
            }
        }
    }
    // server.js
    let express = require('express');
    let app = express();
    app.use(express.static(__dirname));
    app.listen(3000);
    // nginx.conf
    location / {// 代表输入/时默认去打开root目录下的html文件夹
        root html;
        index index.html index.htm;
    }
    location ~.*\.json{//代表输入任意.json后去打开json文件夹
        root json;
        add_header "Access-Control-Allow-Origin" "*";
    }

    http-proxy-middleware

    NodeJS 中间件 http-proxy-middleware 实现跨域代理,原理大致与 nginx 相同,都是通过启一个代理服务器,实现数据的转发,也可以通过设置 cookieDomainRewrite 参数修改响应头中 cookie 中的域名,实现当前域的 cookie 写入,方便接口登录认证。
    • vue框架:利用 node + webpack + webpack-dev-server 代理接口跨域。在开发环境下,由于 Vue 渲染服务和接口代理服务都是 webpack-dev-server,所以页面与代理接口之间不再跨域,无须设置 Headers 跨域信息了。
    module.exports = {
        entry: {},
        module: {},
        ...
        devServer: {
            historyApiFallback: true,
            proxy: [{
                context: '/login',
                target: 'http://www.proxy2.com:8080',  // 代理跨域目标接口
                changeOrigin: true,
                secure: false,  // 当代理某些 https 服务报错时用
                cookieDomainRewrite: 'www.domain1.com'  // 可以为 false,表示不修改
            }],
            noInfo: true
        }
    }
    • 非vue框架的跨域(2 次跨域)
    
    
    
    
        
        nginx跨域
    
    
        
    
    
    // 中间代理服务器
    var express = require("express");
    var proxy = require("http-proxy-middleware");
    var app = express();
    
    app.use(
        "/",
        proxy({
            // 代理跨域目标接口
            target: "http://www.proxy2.com:8080",
            changeOrigin: true,
    
            // 修改响应头信息,实现跨域并允许带 cookie
            onProxyRes: function(proxyRes, req, res) {
                res.header("Access-Control-Allow-Origin", "http://www.proxy1.com");
                res.header("Access-Control-Allow-Credentials", "true");
            },
    
            // 修改响应信息中的 cookie 域名
            cookieDomainRewrite: "www.proxy1.com" // 可以为 false,表示不修改
        })
    );
    
    app.listen(3000);
    // 服务器
    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.proxy2.com;HttpOnly" // HttpOnly:脚本无法读取
        });
    
        res.write(JSON.stringify(params));
        res.end();
    });
    
    server.listen("8080");

    你可能感兴趣的:(跨域,javascript)