浏览器跨域解决方案

一.同源策略

  1. 什么是同源策略?

    是浏览器的一个安全功能,不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源。所以a.com下的JS脚本采用ajax读取b.com里面的文件数据是会报错的。 (协议,域名,端口号三者都要相同)

  2. 不受同源策略限制

    1、页面中的链接,重定向以及表单提交是不会受到同源策略限制的。

    2、跨域资源的引入是可以的。但是JS不能读写加载的内容。如嵌入到页面中的 <script src="..."></script><img><link><iframe>等。

二.跨域

  1. JSONP

    通常为了减轻web服务器的负载,我们把JS、CSS,IMG等静态资源分离到另一台独立域名的服务器上,在html页面中再通过相应的标签从不同域名下加载静态资源,而被浏览器允许,基于此原理,我们可以通过动态创建script,再请求一个带参网址实现跨域通信。

    缺点:只能实现get请求

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <script>
    var script = document.createElement('script');
    script.type = 'text/javascript';
    // 传参一个回调函数名给后端,方便后端返回时执行这个在前端定义的回调函数
    script.src = 'http://www.domain2.com:8080/login?user=admin&callback=handleCallback';
    document.head.appendChild(script);
    // 回调执行函数
    function handleCallback(res) {
    alert(JSON.stringify(res));
    }
    </script>
  2. 跨域资源共享(CORS)

    1.不带cookies 设置 Access-Control-Allow-Origin

    2.带cookies 设置 Access-Control-Allow-Credentials

  3. NGINX反向代理

    跨域原理: 同源策略是浏览器的安全策略,不是HTTP协议的一部分。服务器端调用HTTP接口只是使用HTTP协议,不会执行JS脚本,不需要同源策略,也就不存在跨越问题。

    实现思路:通过nginx配置一个代理服务器(域名与domain1相同,端口不同)做跳板机,反向代理访问domain2接口,并且可以顺便修改cookie中domain信息,方便当前域cookie写入,实现跨域登录。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #proxy服务器
    server {
    listen 81;
    server_name www.domain1.com;
    location / {
    proxy_pass http://www.domain2.com:8080; #反向代理
    proxy_cookie_domain www.domain2.com www.domain1.com; #修改cookie里域名
    index index.html index.htm;
    # 当用webpack-dev-server等中间件代理接口访问nignx时,此时无浏览器参与,故没有同源限制,下面的跨域配置可不启用
    add_header Access-Control-Allow-Origin http://www.domain1.com; #当前端只跨域不带cookie时,可为*
    add_header Access-Control-Allow-Credentials true;
    }
    }
    1
    2
    3
    4
    5
    6
    var xhr = new XMLHttpRequest();
    // 前端开关:浏览器是否读写cookie
    xhr.withCredentials = true;
    // 访问nginx中的代理服务器
    xhr.open('get', 'http://www.domain1.com:81/?user=admin', true);
    xhr.send();
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    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.domain2.com;HttpOnly' // HttpOnly:脚本无法读取
    });
    res.write(JSON.stringify(params));
    res.end();
    });
    server.listen('8080');
    console.log('Server is running at port 8080...');
  4. Nodejs中间件代理跨域

  5. WebSocket协议跨域

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    <div>user input:<input type="text"></div>
    <script src="https://cdn.bootcss.com/socket.io/2.2.0/socket.io.js"></script>
    <script>
    var socket = io('http://www.domain2.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>
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    var http = require('http');
    var socket = require('socket.io');
    // 启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.');
    });
    });

浏览器跨域解决方案
https://jing-jiu.github.io/jing-jiu/2020/04/07/前端基础/浏览器安全/
作者
Jing-Jiu
发布于
2020年4月7日
许可协议