美文网首页Web 前端开发 让前端飞程序员
2017.12.11-学习笔记:聊聊同源跨域 Jsonp、COR

2017.12.11-学习笔记:聊聊同源跨域 Jsonp、COR

作者: bixin | 来源:发表于2017-12-11 16:28 被阅读73次

    同源策略

    • 指的是浏览器对不同源的脚本或者文本的访问方式进行的限制。比如源a的js不能读取或者设置引入的源b的元素属性

    • 同源的三要素:

      • 相同的协议
      • 相同的域名
      • 相同的端口号
    • 同源策略限制的不同之间的交互主要针对的js中的XMLHttpRequest等请求,下面这些情况是完全不受同源策略限制的

      • 页面中的链接,重定向以及表单提交是不会受到同源策略限制的。
        链接就不用说了,导航网站上的链接都是链接到其他站点的。而你在域名www.a.com下面提交一个表单到www.b.com是完全可以的。
      • 跨域资源嵌入是允许的,当然,浏览器限制了JavaScript不能读写加载的内容。
        如前面提到的嵌入的<script src="..."></script>,<img>,<link>,<iframe>。
    • 存在的意义:

      • 为了保证使用者信息的安全,防止恶意网站篡改用户数据
        ajax同源策略主要用来防止CSRF攻击。如果没有ajax同源策略,相当危险,我们发起的每一次HTTP请求都会带上请求地址对应的cookie,那么可以做如下攻击:
        • 1.用户登录了自己的银行页面 mybank.com , mybank.com 向用户的 cookie 中添加用户标识。
        • 2.用户浏览了恶意页面 evil.com 执行了页面中的恶意ajax请求代码
        • 3.evil.com 向 mybank.com 发起ajax HTTP请求,请求会默认把mybank.com 对应cookie 也同时发送过去
        • 4.银行页面从发送的cookie 中提取用户标识,验证用户无误,response中返回请求数据。此时数据就泄露了
        • 5.而且用于ajax在后台执行,用户无法感知这一过程
    • 限制范围(非同源的网站之间)

      • 无法共享cookie,localstorage,indexDB
      • 无法操作彼此的dom元素
      • 无法发送ajax请求
      • 无法通过flash发送http请求

    跨域

    • 指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对JavaScript事件的安全限制
    • 域名,协议,端口有一个不同都会造成跨域。
      localhost和127.0.0.1虽然都指向本机,但也属于跨域。
      浏览器执行JavaScript脚本时,会检查这个脚本属于哪个页面,如果不是同源页面,就不会被执行。

    跨域解决办法:Jsonp、CORS、Nginx反向代理

    script src 属性 进行 get 请求 js 文件, 不受同源策略限制
    script 标签 只是在请求数据, js文本, php响应的也是js文本,所以, src 也可以引入 php 文件
    浏览器会将获取过来的文本当成 js 来执行

    • 1、JSONP:
      jsonp其实算一种hack形式的请求
      jsonp的本质其实是请求你一段js代码,是对静态文件资源的请求,所以并不遵循同源策略
      因为是对静态文件资源的请求,所以jsonp只支持get请求,不支持POST请求
      ajax的核心是通过XMLHttpRequest获取非本页内容,而jsonp的核心则是动态添加<script>标签来调用服务器提供的js脚本。
      jsonp的诞生
      1.首先,因为ajax无法跨域,然后开发者就有所思考
      2.其次,开发者发现,<script>标签的src属性是可以跨域的,把跨域服务器写成 调用本地的函数,回调数据回来不久好了?
      3.json刚好被js支持(object)
      4.调用跨域服务器上动态生成的js格式文件(不管是什么类型的地址,最终生成的返回值都是一段js代码)
      5.这种获取远程数据的方式看起来非常像ajax,但其实并不一样,便于客户端使用数据,逐渐形成了一种非正式传输协议,人们把它称作jsonp
      6.传递一个callback参数给跨域服务端,然后跨域服务端返回数据时会将这个callback参数作为函数名来包裹住json数据即可。

      • jsonp应用

    1.服务端JSONP格式数据
    如客户想访问 : http://www.jsonp.com/try/ajax/jsonp.php?jsonp=callbackFunction
    假设客户期望返回JSON数据:["customername1","customername2"]。
    真正返回到客户端的数据显示为: callbackFunction(["customername1","customername2"])。
    服务端文件jsonp.php代码为:

    <?php
    header('Content-type: application/json');
    //获取回调函数名
    $callback = $_GET['callback'];
    //json数据
    $json_data = '["customername1","customername2"]';
    //输出jsonp格式的数据
    echo $callback . "(" . $json_data . ")";
    ?>
    

    2.客户端实现 callbackFunction 函数

    <script type="text/javascript">
      function callbackFunction(result, methodName) {
        var html = '<ul>';
        for (var i = 0; i < result.length; i++) {
          html += '<li>' + result[i] + '</li>';
        }
        html += '</ul>';
        document.getElementById('divCustomers').innerHTML = html;
      }
    </script>
    

    3.客户端页面完整代码

    <!DOCTYPE html>
    <html>
    
    <head>
      <meta charset="utf-8">
      <title>JSONP 实例</title>
    </head>
    
    <body>
      <div id="divCustomers"></div>
      <script type="text/javascript">
        function callbackFunction(result, methodName) {
          var html = '<ul>';
          for (var i = 0; i < result.length; i++) {
            html += '<li>' + result[i] + '</li>';
          }
          html += '</ul>';
          document.getElementById('divCustomers').innerHTML = html;
        }
      </script>
      <script type="text/javascript" src="http://www.jsonp.com/try/ajax/jsonp.php?callback=callbackFunction"></script>
    
    <!-- script标签可以是动态生成,放到事件中可以触发事件才获取数据
        // 动态创建 script 标签, 请求数据
        var script = document.createElement("script");
        // 设置src请求数据
        script.src = "http://www.jsonp.com/try/ajax/jsonp.php?callback=callbackFunction";
        // 将 script 添加到 头部中去
        document.head.appendChild( script );-->
    </body>
    
    </html>
    

    4.jQuery 使用 JSONP

    <!DOCTYPE html>
    <html>
    
    <head>
      <meta charset="utf-8">
      <title>JSONP 实例</title>
      <script src="http://cdn.static.runoob.com/libs/jquery/1.8.3/jquery.js"></script>
    </head>
    
    <body>
      <div id="divCustomers"></div>
      <script>
        $.getJSON("http://www.jsonp.com/try/ajax/jsonp.php?callback=?", function(data) {
    
          var html = '<ul>';
          for (var i = 0; i < data.length; i++) {
            html += '<li>' + data[i] + '</li>';
          }
          html += '</ul>';
    
          $('#divCustomers').html(html);
        });
      </script>
    </body>
    
    </html>
    
    • 2、跨域资源共享(CORS):
      普通跨域请求:只服务端设置Access-Control-Allow-Origin即可,前端无须设置,若要带cookie请求:前后端都需要设置。
      1.前端设置
    // 原生ajax
    
    var xhr = new XMLHttpRequest(); // IE8/9需用window.XDomainRequest兼容
    // 前端设置是否带cookie
    xhr.withCredentials = true;
    xhr.open('post', 'http://www.domain2.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);
      }
    }
    
    -------------------------
    
    // jQuery
    
    $.ajax({
      ...
      xhrFields: {
        withCredentials: true // 前端设置是否带cookie
      },
      crossDomain: true, // 会让请求头中包含跨域的额外信息,但不会含cookie
      ...
    });
    

    2.后台设置

      /*
       * 导入包:import javax.servlet.http.HttpServletResponse;
       * 接口参数中定义:HttpServletResponse response
       */
      response.setHeader("Access-Control-Allow-Origin", "http://www.domain1.com"); // 若有端口需写全(协议+域名+端口)
      response.setHeader("Access-Control-Allow-Credentials", "true");
    
    • 3、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;
      }
    }
    

    1.前端设置:

    var xhr = new XMLHttpRequest();
    // 前端开关:浏览器是否读写cookie
    xhr.withCredentials = true;
    // 访问nginx中的代理服务器
    xhr.open('get', 'http://www.domain1.com:81/?user=admin', true);
    xhr.send();
    

    2.nodejs后台:

    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、webpack-dev-server配置proxy
      webpack 内置了 http-proxy-middleware 可以解决 请求的 URL 代理的问题
      配置:
    module.exports = {
      devtool: 'cheap-module-source-map',
      entry: './app/js/index.js'
      output: {
        path: path.resolve(__dirname, 'dev'),
        // 所有输出文件的目标路径
        filename: 'js/bundle.js',
        publicPath: '/',
        chunkFilename: '[name].chunk.js'
      },
      devServer: {
        contentBase: path.resolve(__dirname, 'dev'),
        publicPath: '/',
        historyApiFallback: true,
        proxy: {
          // 请求到 '/device' 下 的请求都会被代理到 target: http://debug.xxx.com 中
          '/device/*': {
            target: 'http://debug.xxx.com',
            secure: false, // 接受 运行在 https 上的服务
            changeOrigin: true
          }
        }
      }
    }
    



    Knowledge changes the mind

    相关文章

      网友评论

        本文标题:2017.12.11-学习笔记:聊聊同源跨域 Jsonp、COR

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