美文网首页
前端跨域整理

前端跨域整理

作者: dosher_多舍 | 来源:发表于2019-03-18 17:33 被阅读0次

什么是跨域?

跨域是指一个域下的文档或脚本试图去请求另一个域下的资源,这里的跨域是广义的。

广义的跨域:

  1. 资源跳转:a链接、重定向、表单提交;
  2. 资源嵌入:<link>、<script>、<img>、<frame>等DOM标签
  3. 脚本请求:ajax、dom对象跨域操作等。

狭义的跨域:
其实我们通常所说的跨域是狭义的,是由浏览器同源策略限制的一类请求场景。

同源策略/SOP(Same origin policy)是一种约定,由Netscape公司1995年引入浏览器,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSFR等攻击。所谓同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个ip地址,也非同源。

同源策略限制一下几种行为:

  1. Cookie、LocalStorage和IndexDB无法获取
  2. DOM和JS对象无法获得
  3. Ajax请求不能发送

常见跨域场景:

场景                     | example                      | 是否允许通信

同一域名,不同文件或路径     | http://www.a.com/a           | 允许
                         | http://www.a.com/b           |

同一域名,不同端口          | http://www.a.com:8082/a      | 不允许
                         | http://www.a.com/a           |

同一域名,不同协议          | http://www.a.com/a           | 不允许
                         | https://www.a.com/a          |

同一IP,不同域名            | http://www.a.com/a           | 不允许
                         | http://192.168.1.1/a         |

主域名相同,子域名不同       | http://www.a.com/a           | 不允许
                         | http://domain.a.com/a        |

不同域名,                 | http://www.a.com/a           | 不允许
                         | http://www.b.com/a           |

跨域的解决方案

  1. 通过jsonp跨域;

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

    原理:

    // 前端
    <script>
        var script = document.createElement('script');
        script.type = 'text/javascript';
    
        // 传参并指定回调执行函数为onBack
        script.src = 'http://www.a.com/login?user=admin&callback=onBack';
        document.head.appendChild(script);
    
        // 回调执行函数
        function onBack(res) {
            alert(JSON.stringify(res));
        }
     </script>
     
     // 服务器返回如下(返回时即执行全局函数)
     onBack({"status": true, "user": "admin"})
    

    JSONP缺点:只能实现get一种请求。

  2. 跨域资源共享(CORS);

    普通跨域请求:只服务端设置Access-Control-Allow-Origin即可,前端无须设置,若要带cookie请求:前后端都需要设置。(需注意的是:由于同源策略的限制,所读取的cookie为跨域请求接口所在域的cookie,而非当前页。

    Java后台:

    /*
     * 导入包:import javax.servlet.http.HttpServletResponse;
     * 接口参数中定义:HttpServletResponse response
     */
    
    // 允许跨域访问的域名:若有端口需写全(协议+域名+端口),若没有端口末尾不用加'/'
    response.setHeader("Access-Control-Allow-Origin", "http://www.domain1.com"); 
    
    // 允许前端带认证cookie:启用此项后,上面的域名不能为'*',必须指定具体的域名,否则浏览器会提示
    response.setHeader("Access-Control-Allow-Credentials", "true"); 
    
    // 提示OPTIONS预检时,后端需要设置的两个常用自定义头
    response.setHeader("Access-Control-Allow-Headers", "Content-Type,X-Requested-With");
    

    nodejs后台:

    var 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.domain1.com',    // 允许访问的域(协议+域名+端口)
                /* 
                 * 此处设置的cookie还是domain2的而非domain1,因为后端也不能跨域写cookie(nginx反向代理可以实现),
                 * 但只要domain2中写入一次cookie认证,后面的跨域接口都能从domain2中获取cookie,从而实现所有的接口都能跨域访问
                 */
                'Set-Cookie': 'l=a123456;Path=/;Domain=www.domain2.com;HttpOnly'  // HttpOnly的作用是让js无法读取cookie
            });
    
            res.write(JSON.stringify(postData));
            res.end();
        });
    });
    
    server.listen('8080');
    console.log('Server is running at port 8080...');
    

    CORS也已经成为主流的跨域解决方案。

  3. nginx代理跨域;

    nginx配置解决iconfont跨域

    浏览器跨域访问js、css、img等常规静态资源被同源策略许可,但iconfont字体文件(eot|otf|ttf|woff|svg)例外,此时可在nginx的静态资源服务器中加入以下配置。

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

    nginx反向代理接口跨域

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

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

    nginx具体配置:

    #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;
        }
    }
    
  4. nodejs中间件代理跨域;

    node中间件实现跨域代理,原理大致与nginx相同,都是通过启一个代理服务器,实现数据的转发,也可以通过设置cookieDomainRewrite参数修改响应头中cookie中域名,实现当前域的cookie写入,方便接口登录认证。

  5. webSocket协议跨域;

    WebSocket protocol是HTML5一种新的协议。它实现了浏览器与服务器全双工通信,同时允许跨域通讯,是server push技术的一种很好的实现。

  6. postMessage跨域;

    postMessage是HTML5 XMLHttpRequest Level 2中的API,且是为数不多可以跨域操作的window属性之一,它可用于解决以下方面的问题

    • 页面和其打开的新窗口的数据传递;
    • 多窗口之间消息传递;
    • 页面与嵌套的iframe消息传递;

    用法:postMessage(data,origin)方法接受两个参数

    data: html5规范支持任意基本类型或可复制的对象,但部分浏览器只支持字符串,所以传参时最好用JSON.stringify()序列化。

    origin: 协议+主机+端口号,也可以设置为"*",表示可以传递给任意窗口,如果要指定和当前窗口同源的话设置为"/"。

    1. a.html
    <iframe id="iframe" src="http://www.domain2.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.domain2.com');
        };
    
        // 接受domain2返回数据
        window.addEventListener('message', function(e) {
            alert('data from domain2 ---> ' + e.data);
        }, false);
    </script>
    
    1. b.html
    <script>
        // 接收domain1的数据
        window.addEventListener('message', function(e) {
            alert('data from domain1 ---> ' + e.data);
    
            var data = JSON.parse(e.data);
            if (data) {
                data.number = 16;
    
                // 处理后再发回domain1
                window.parent.postMessage(JSON.stringify(data), 'http://www.domain1.com');
            }
        }, false);
    </script>
    

相关文章

  • 浏览器跨域的那些事

    整理中 目标: 了解跨域 解决跨域 服务器配置跨域(java, nginx) 前端调试时配置解决跨域 一、什么是跨...

  • 前端跨域整理

    前言 原文地址:前端跨域总结 博主博客地址:Damonare的个人博客 相信每一个前端er对于跨域这两个字都不会陌...

  • 前端跨域整理

    前言 原文地址:前端跨域总结博主博客地址:Damonare的个人博客 正文 1. 什么是跨域? 跨域一词从字面意思...

  • 前端跨域整理

    前言 相信每一个前端er对于跨域这两个字都不会陌生,在实际项目中应用也是比较多的。但跨域方法的多种多样实在让人目不...

  • 前端跨域整理

    什么是跨域? 跨域是指一个域下的文档或脚本试图去请求另一个域下的资源,这里的跨域是广义的。 广义的跨域: 资源跳转...

  • 关于设置env等环境变量的思考

    1、如何处理跨域后台处理跨域前端处理跨域浏览器处理跨域 前端本地处理跨域:代理线上跨域的处理方式:Nginx反向代...

  • 前端跨域

    转载自:https://segmentfault.com/a/1190000007326671bo 前端跨域整理 ...

  • 实现跨域请求的八种方式

    前端开发中我们经常会遇到跨域请求的情况,处理跨域请求方式很多,特整理如下: 浏览器的同源策略 提到跨域不能不先说一...

  • 前端跨域请求方法整理

    前端跨域请求方法整理 什么是跨域请求 浏览器的同源策略,出于防范跨站脚本的攻击,禁止客户端脚本(如 JavaScr...

  • 前端跨域的整理

    跨域资源共享 CORS 对于web开发来讲,由于浏览器的同源策略,我们需要经常使用一些hack的方法去跨域获取资源...

网友评论

      本文标题:前端跨域整理

      本文链接:https://www.haomeiwen.com/subject/jcubmqtx.html