• 前端跨域


    一、同源策略

    同源策略限制从一个源的资源如何与另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的关键机制。

    二、怎样算同源

    两个页面的协议、域名和端口完全相同,则两个页面是同源的。

    三、同源限制范围

    (1)Cookie , LocalStorage, IndexedDB 数据读取限制

    (2)DOM无法获取。如iframe 窗口和window.open方法打开的窗口,无法与父窗口通信

    (3)Ajax请求发送限制

    四、什么是跨域

    协议、域名、端口 有一个不同,就是不同域。对于协议和端口不同的跨域,只能通过后台解决。

     五、常用跨域的解决方案

    (一)、跨域资源共享(CORS)——解决Ajax同源请求限制

    概述:CORS允许Web应用服务器进行跨域访问,浏览器支持在API容器中(如XHR或Fetch)中使用CORS。 CORS需要浏览器与服务器的同时支持。目前IE10以上的浏览器都支持了该功能。因此,实现CORS的关键是服务器,必须要服务端实现了CORS接口,才实现跨域通信。浏览器端一旦发现Ajax请求跨域,会自动增加附加头信息。CORS新增了一组http头部字段,允许服务器声明哪些源站有权限访问哪些资源。对可能产生副作用的http请求,浏览器必须首先使用OPTIONS方法发起一个预检请求,在得到服务器允许确认允许后,才发起实际的http请求。

    应用场景:——————简单请求、预检请求、带身份凭证(Cookie)的请求,以XHR为例,fetch同理,但按fetch标准略有不同

    1、简单请求 

    //request head
    GET /resources/public-data/ HTTP/1.1 Host: bar.other User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip,deflate Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Connection: keep-alive Referer: http://foo.example/examples/access-control/simpleXSInvocation.html Origin: http://foo.example //response HTTP/1.1 200 OK Date: Mon, 01 Dec 2008 00:23:53 GMT Server: Apache/2.0.61 Access-Control-Allow-Origin: * //*表示可以被任何域访问。如果仅仅允许http://foo.example 则将*替换为该地址即可 Keep-Alive: timeout=2, max=100 Connection: Keep-Alive Transfer-Encoding: chunked Content-Type: application/xml

     使用Origin 和Access-Control-Allow-Origin 就能完成最简单的访问控制。

    2、预检请求

     当请求满足下列任一条件时,应该首先发送预检请求:

    • 使用了下面任意http方法: put  delect  connect  options  trace patch
    • 人为设置了CORS安全的首部字段集合之外的其他首部字段。即:

     需要预检的http请求示例:

    var invocation = new XMLHttpRequest();
    var url = 'http://bar.other/resources/post-here/';
    var body = '<?xml version="1.0"?><person><name>Arun</name></person>';
        
    function callOtherDomain(){
      if(invocation)
        {
          invocation.open('POST', url, true);
          invocation.setRequestHeader('X-PINGOTHER', 'pingpong');                     //需要预检的http请求
          invocation.setRequestHeader('Content-Type', 'application/xml');             //需要预检的http请求  
          invocation.onreadystatechange = handler;
          invocation.send(body); 
        }
    }

     预检请求

    //request head
    OPTIONS /resources/post-here/ HTTP/1.1 //使用options方法的预检请求 Host: bar.other User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip,deflate Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Connection: keep-alive Origin: http://foo.example Access-Control-Request-Method: POST //告知服务器,实际请求将是POST方法 Access-Control-Request-Headers: X-PINGOTHER, Content-Type //告知服务器,请求将携带两个自定义首部字段X-PINGOTHER 和Content-Type。 服务器据此决定该请求是否被允许
    //response
    HTTP/1.1 200 OK Date: Mon, 01 Dec 2008 01:15:39 GMT 
    Server: Apache/2.0.61 (Unix)
    Access-Control-Allow-Origin: http://foo.example //允许的域为http://foo.example
    Access-Control-Allow-Methods: POST, GET, OPTIONS //允许使用POST GET OPTIONS发送请求
    Access-Control-Allow-Headers: X-PINGOTHER, Content-Type //允许头部字段中携带 X-PINGOTHER, Content-Type
    Access-Control-Max-Age: 86400 //改响应的有效时间为86400s。在有效期内浏览器无需为同一请求发起预检请求
    Vary: Accept-Encoding, Origin
    Content-Encoding: gzip
    Content-Length: 0
    Keep-Alive: timeout=2, max=100
    Connection: Keep-Alive
    Content-Type: text/plain

     预检请求通过后发送实际请求

    //request head
    POST /resources/post-here/ HTTP/1.1 Host: bar.other User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip,deflate Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Connection: keep-alive X-PINGOTHER: pingpong Content-Type: text/xml; charset=UTF-8 Referer: http://foo.example/examples/preflightInvocation.html Content-Length: 55 Origin: http://foo.example Pragma: no-cache Cache-Control: no-cache <?xml version="1.0"?><person><name>Arun</name></person> //response HTTP/1.1 200 OK Date: Mon, 01 Dec 2008 01:15:40 GMT Server: Apache/2.0.61 (Unix) Access-Control-Allow-Origin: http://foo.example Vary: Accept-Encoding, Origin Content-Encoding: gzip Content-Length: 235 Keep-Alive: timeout=2, max=99 Connection: Keep-Alive Content-Type: text/plain [Some GZIP'd payload]

    3、带身份凭证(Cookie)的请求

     对于跨域的XHR和Fetch请求,浏览器不会发送身份凭证信息,如需发送,需要设置XHR的特殊标记withCredentials

    带Cookie的跨域请求示例

    var invocation = new XMLHttpRequest();
    var url = 'http://bar.other/resources/credentialed-content/';
        
    function callOtherDomain(){
      if(invocation) {
        invocation.open('GET', url, true);
        invocation.withCredentials = true;         //携带cookie发送请求,服务端需要携带Access-Control-Allow-Credentials:ture, 否则浏览器不会把响应给请求发送者
        invocation.onreadystatechange = handler;
        invocation.send(); 
      }
    }

    携带Cookie的请求响应

    //request head
    GET /resources/access-control-with-credentials/ HTTP/1.1
    Host: bar.other
    User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
    Accept-Language: en-us,en;q=0.5
    Accept-Encoding: gzip,deflate
    Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
    Connection: keep-alive
    Referer: http://foo.example/examples/credential.html
    Origin: http://foo.example
    Cookie: pageAccess=2
    
    //response
    HTTP/1.1 200 OK
    Date: Mon, 01 Dec 2008 01:34:52 GMT
    Server: Apache/2.0.61 (Unix) PHP/4.4.7 mod_ssl/2.0.61 OpenSSL/0.9.7e mod_fastcgi/2.4.2 DAV/2 SVN/1.4.2
    X-Powered-By: PHP/5.2.6
    Access-Control-Allow-Origin: http://foo.example
    Access-Control-Allow-Credentials: true
    Cache-Control: no-cache
    Pragma: no-cache
    Set-Cookie: pageAccess=3; expires=Wed, 31-Dec-2008 01:34:53 GMT
    Vary: Accept-Encoding, Origin
    Content-Encoding: gzip
    Content-Length: 106
    Keep-Alive: timeout=2, max=100
    Connection: Keep-Alive
    Content-Type: text/plain

    注:带身份凭证的请求Access-Control-Allow-Origin 值不可设置为“*”,需要指明具体值,否则请求会失败。

    (二)、JSONP

    JSONP由两部分组成:

    • 回调函数        当响应来到时页面中该调用的函数,回调函数名在请求中指定
    • 数据     传入回调函数中的JSON数据

    JSONP跨域步骤:

      1、浏览器构造请求地址  

    标准的script请求地址为: 请求的资源地址 + 获取函数的字段名 + 回调函数名。 获取函数的字段名需要客户端服务端共同约定,如jquery中默认为callback。

    function resolveJson(result) {
        console.log(result.name);
    }
    var jsonpScript= document.createElement("script");
    jsonpScript.type = "text/javascript";
    jsonpScript.src = "http://www.qiute.com?callbackName=resolveJson";     //callbackName 获取函数的字段名  resolveJson回调函数
    document.getElementsByTagName("head")[0].appendChild(jsonpScript);

      2、服务端构造返回

    在收到浏览器的请求后,从url中按约定的获取函数字段寻找回调函数名,即按照callbackName找到了回调函数为resolveJson,然后将数据传入回调函数

    resolveJson({name: 'qiutc'});

      3、客户端以脚本方式执行客户端返回值    客户端拿到回调数据后,自行处理

      

    参考:

    JavaScript高级程序设计

    https://developer.mozilla.org/zh-CN/docs/Web/Security/Same-origin_policy 浏览器的同源策略

    http://www.ruanyifeng.com/blog/2016/04/same-origin-policy.html 浏览器的同源策略及其规避方法

    https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS http访问控制

    https://segmentfault.com/a/1190000006095018   浏览器跨域方法与基于Fetch的Web请求最佳实践

    https://segmentfault.com/a/1190000000718840  详解js跨域问题

    https://github.com/camsong/blog/issues/2   fetch简介

  • 相关阅读:
    20210519日报
    20210518日报
    20210517日报
    20210514日报
    20210513日报
    20210512日报
    20210511日报
    数据挖掘提分三板斧-转
    特征变量和y值的可视化
    kaggle 2015年航班延误
  • 原文地址:https://www.cnblogs.com/xxchi/p/8288421.html
Copyright © 2020-2023  润新知