• 跨域问题


         跨域是个老生常谈的跨题。今天在我们后端的帮助和配合下,对跨域又多了一层认识。感觉对于每件事,只要是从3个方面(what,why,how)去理解,都会对其有个基本(70%)认识。

         好记性不如烂笔头,针对跨域,我总结了以下3个问题。1、为什么产生跨域问题? 2、如何解决以及原理? 3、每种方式各有什么优缺点。

    一、是什么?

          跨域是由于同源策略(同域名,同端口,同协议)的限制导致的,即浏览器从一个域名的网页去请求另一个域名的资源时,域名、端口、协议任一不同,都是跨域 。

    域名:
        主域名不同 http://www.baidu.com/index.html –>http://www.sina.com/test.js
        子域名不同 http://www.666.baidu.com/index.html –>http://www.555.baidu.com/test.js
        域名和域名ip http://www.baidu.com/index.html –>http://180.149.132.47/test.js
    端口:
         http://www.baidu.com:8080/index.html–> http://www.baidu.com:8081/test.js
    协议:
         http://www.baidu.com:8080/index.html–> https://www.baidu.com:8080/test.js
    备注:
        1、端口和协议的不同,只能通过后台来解决
        2、localhost和127.0.0.1虽然都指向本机,但也属于跨域

    二、为什么产生跨域

          为了安全性考虑,AJAX同源策略只要是为了防止 CSRF攻击

    三、如何解决跨域以及原理

    1、jsonp

     

          原理: 由于同源策略的限制,XmlHttpRequest只允许请求当前源(域名、协议、端口)的资源。若要跨域请求出于安全性考虑是不行的,但是我们发现,Web页面上调用js文件时则不受是否跨域的影响,简单的说,就是利用script标签没有跨域限制的“漏洞”来达到与第三方通讯的目的,或者更确切地说,拥有”src”这个属性的标签都拥有跨域的能力,比如<script>、<img>、<iframe>,这时候,聪明的程序猿就想到了变通的方法,如果要进行跨域请求, 通过使用html的script标记来进行跨域请求,并在响应中返回要执行的script代码,其中可以直接使用JSON传递 javascript对象。即在跨域的服务端生成JSON数据,然后包装成script脚本回传,就可以突破同源策略的限制,解决了跨域访问的问题了。

         
          过程:首先在客户端注册一个callback,然后把callback的名字传给服务器。此时,服务器先生成json数据,然后以javascript语法的方式,生成function,function名字就是传递上来I带参数jsonp。最后将json数据直接以入参的方式,放置function中,这样就生成js语法的文档,返回给客户端。客户端浏览器,解析script变迁,并执行返回javascript文档,此时数据作为参数,传入了客户端预先定义好的callback函数里。然后客户端就可以得到callback函数带的参数,并对该数据进行处理展示。

         

          注意:利用 <script> 元素的这个开放策略,网页可以得到从其他来源动态产生的 JSON 资料,而这种使用模式就是所谓的 JSONP。用 JSONP 抓到的资料并不是 JSON,JSON返回的是一串数据、JSONP返回的是脚本代码(包含一个函数调用) ,是任意的JavaScript,用 JavaScript 直译器执行而不是用 JSON 解析器解析。

          缺点: JSONP 只支持get请求、不支持post请求  (类似往页面添加一个script标签,通过src属性去触发对指定地址的请求,故只能是Get请求)

    如下,是用jquery的jsonp请求方式:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Jsonp Test</title>
    </head>
    <body>
    <input type="button" id="json" value="json test">
    <br/>
    <input type="button" id="jsonp" value="jsonp test">
    </body>
    <script src="https://code.jquery.com/jquery-3.3.1.min.js"
            integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
            crossorigin="anonymous"></script>
    <script>
        $(function () {
            $("#jsonp").click(function () {
                $.ajax({
                    url: "https://dev.baihuzi.cn/pj/jsonp.php",
                    type: "get",
                    dataType: "jsonp",
                    jsonpCallback: "tttt"
                })
                .done(function(data) {//请求成功的回调函数
                    console.log(data)
                 })
                .fail(function() {
                    alert('服务器超时,请重试!');
                });
            });
    
            $("#json").click(function () {
                $.ajax({
                    url: "https://dev.baihuzi.cn/pj/json.php",
                    type: "get",
                    dataType: "json",
                })
                    .done(function(data) {//请求成功的回调函数
                        console.log(data)
                    })
                    .fail(function() {
                        alert('服务器超时,请重试!');
                    });
            });
    
        })
    
    </script>
    </html>

    2、cors

    Cors的英文全称是Cross-origin Resource Sharing,意思是跨域资源共享。它允许浏览器向非同源服务器发送XMLHttpRequest请求,能够像访问同源本地服务器一般。Cors需要浏览器和服务器同时支持,现在的主流浏览器(Google/IE/FireFox/360)一般都支持跨域的,所以关键在于服务器端实现跨域问题,才能真正实现跨域通信。

    PHP端修改header 
      header(‘Access-Control-Allow-Origin:*’);//允许所有来源访问 
      header(‘Access-Control-Allow-Method:POST,GET’);//允许访问的方式 

    3、nginx反向代理

          项目前后端分离后,前后端项目分开开发,尤其是单页面应用,前端代码会开启单独的服务器,若直接在前端项目中访问后端API,肯定会遇到因跨域不能访问的问题。这时候,用nginx反向代理实现跨域,是最简单的跨域方式。只需要修改nginx的配置即可解决跨域问题,支持所有浏览器,支持session,不需要修改任何代码,并且不会影响服务器性能。

          我们只需要配置nginx,在一个服务器上配置多个前缀来转发http/https请求到多个真实的服务器即可。这样,这个服务器上所有url都是相同的域名、协议和端口。因此,对于浏览器来说,这些url都是同源的,没有跨域限制。而实际上,这些url实际上由物理服务器提供服务。这些服务器内的javascript可以跨域调用所有这些服务器上的url。

          将nginx目录下的nginx.conf修改如下,这里配置了两台server,如果只需一台,把其中一个server删除即可。之所以配置两台服务器,是前端可能同时在开发两个项目,或者同一个项目开发环境和生成环境各自开启一个服务,方便调试。

    4、postMessage 

    5、window.name 

         

    总结

    浏览器跨域的解决方式有很多种:

          1.jsonp 需要目标服务器配合一个callback函数。

      2.window.name+iframe 需要目标服务器响应window.name。

      3.window.location.hash+iframe 同样需要目标服务器作处理。

      4.html5的 postMessage+ifrme 这个也是需要目标服务器或者说是目标页面写一个postMessage,主要侧重于前端通讯。

      5.CORS  需要服务器设置header :Access-Control-Allow-Origin。

      6.nginx反向代理 这个方法一般很少有人提及,但是该方式可以不用目标服务器配合,不过需要你搭建一个中转nginx服务器,用于转发请求(比较正规)。

    参考链接   http://www.ruanyifeng.com/blog/2016/04/same-origin-policy.html

  • 相关阅读:
    大部分人都会做错的经典JS闭包面试题
    20071109 QQ群:ITIL和ITSM 聊天记录,欢迎大家加入QQ群:48132184
    模式窗口window.open造成Session丢失的解决方法
    Server.Transfer 方法如何传递复杂的参数
    小游戏测试你的情商
    VS.Net 开发 MSN一样缓慢出来的提示信息的方法
    Javascript 技巧大全
    ASP.NET 2.0,无刷新页面新境界! 【转】
    ASP.NET AJAX入门系列【转】
    asp.net2.0+ajax开发的无刷新聊天室Demo【转】
  • 原文地址:https://www.cnblogs.com/catherLee/p/10102015.html
Copyright © 2020-2023  润新知