zoukankan      html  css  js  c++  java
  • Ajax跨域、Json跨域、Socket跨域和Canvas跨域等同源策略限制的解决方法

    同源是指同样的协议、域名、port,三者都同样才属于同域。不符合上述定义的请求,则称为跨域。

    相信每一个开发者都曾遇到过跨域请求的情况,尽管情况不一样,但问题的本质都能够归为浏览器出于安全考虑下的同源策略的限制。

    跨域的情形有非常多,最常见的有Ajax跨域、Socket跨域和Canvas跨域。以下列举一些我们常见的跨域情形下。某些浏览器控制台给出的错误提示:

    FireFox下的提示:

    已阻止交叉源请求:同源策略不同意读取***上的远程资源。能够将资源移动到同样的域名上或者启用 CORS 来解决问题。

    Canvas跨域Chrome下的提示:

    UncaughtSecurityError:Failed to execute'getImageData' on 'CanvasRenderingContext2D':The canvas has been taintedby cross-origin data.

    或:

    Imagefrom origin 'http://js.xx.com' has been blocked from loading by Cross-OriginResource Sharing policy: No 'Access-Control-Allow-Origin' header is present onthe requested resource. Origin 'http://act.xx.com' is therefore not allowedaccess.


     

    网上有很多解决跨域的方法,大体上有这几种:

    1)document.domain+iframe的设置

    2)动态创建script

    3)利用iframe和location.hash

    4)window.name实现的跨域传输数据

    5)使用HTML5 postMessage

    6)利用flash

    7)通过代理,js訪问代理,代理转到不同的域

    http://developer.yahoo.com/javascript/howto-proxy.html

    8)Jquery JSONP(不能成为真正的Ajax,本质上仍是动态创建script)

    http://www.cnblogs.com/chopper/archive/2012/03/24/2403945.html

    9)跨域资源共享(CORS) 这是HTML5跨域问题的标准解决方式

    说明:方案1~方案6见Rain Man所写的文章《JavaScript跨域总结与解决的方法》

    http://www.cnblogs.com/rainman/archive/2011/02/20/1959325.html

    以下主要就我总结的几种解决跨域的方法。展开说一下。

    1)  绕开跨域。

    适用情形是:动静分离。

    example1.com域名下的页面中跨域请求是以JavaScript内联方式实现的,而请求的目标静态资源是放在example2.com域名下,这时能够将运行跨域请求的JavaScript代码块独立出来,放到example2.com上,而example1.com页面通过外联方式引入该静态域名下的js文件。这样,js与请求的图片等资源都在example2.com下。就可以正常訪问到。这样的方法事实上是一种巧妙避开跨域的方法。

    2)  后台抓取克隆图片。

    适用情形:动静不分离(两个域名均执行訪问静态资源)。

    example1.com请求example2.com下的资源图片,能够使用PHP抓取图片并在example2.com下生成一份,这样就能够间接訪问到example1.com的静态资源。

    html模板演示样例代码:

    $("#scratchpad").wScratchPad({     //刮刮卡演示样例,当前域名http://act.xxx.com

             283,

             height:154,

             //color: "#a9a9a7",

             image2:"imgdata.php?url=http://js.xxx.com/static/activity/sq/guagua315/images/card_inner.jpg",

    scratchMove:function() {

    }

    });

                               

    或:

    xi=newXMLHttpRequest();

    xi.open("GET","imgdata.php?url="+yourImageURL,true);

    xi.send();

     

    xi.onreadystatechange=function() {

      if(xi.readyState==4 && xi.status==200) {

        img=newImage;

        img.onload=function(){

          ctx.drawImage(img, 0, 0, canvas.width, canvas.height);

        }

        img.src=xi.responseText;

      }

    }

    PHP处理代码:

    <?php//imgdata.php

     

      $url=$_GET['url'];

      $img =file_get_contents($url);

      $imgname = substr(strrchr($url,"/"),1);

      file_put_contents($fn,$img);

      echo $imgname;

     

    ?>

    上述代码在当前php文件夹下生成了克隆生成了一张图片。

    3)  后台程序设置Access-Control-Allow-Origin

    适用情形:Ajax获取跨域接口的JSON数据。

    example1.com请求example2.com的数据接口,则须要在example2.com的数据接口加入跨域訪问授权。

    PHP程序中開始出加入header('HeaderName:HeaderValue'); 这种header标记:

    header('Access-Control-Allow-Origin:*');

    4)改动server配置启用CORS

    适用情形:跨域訪问静态资源。

    Access-Control-Allow-Origin是什么作用呢?用于授权资源的跨站訪问。比方,静态资源图片都放在example2.com 域名下, 假设在返回的头中没有设置 Access-Control-Allow-Origin , 那么别的域是没有权限外链你的图片的。

    要实现CORS跨域,服务端须要这个一个流程,图片引自html5rocks,附图例如以下

     

    a.      对于简单请求,如GET。仅仅须要在HTTP Response后加入Access-Control-Allow-Origin。

    b.      对于非简单请求,比方POST、PUT、DELETE等,浏览器会分两次应答。

    第一次preflight(method: OPTIONS)。主要验证来源是否合法。并返回同意的Header等。第二次才是真正的HTTP应答。所以server必须处理OPTIONS应答。

    这里是一个nginx启用CORS的參考配置演示样例http://enable-cors.org/server_nginx.html。代码:

    #
    # A CORS (Cross-Origin Resouce Sharing) config for nginx
    #
    # == Purpose
    #
    # This nginx configuration enables CORS requests in the following way:
    # - enables CORS just for origins on a whitelist specified by a regular expression
    # - CORS preflight request (OPTIONS) are responded immediately
    # - Access-Control-Allow-Credentials=true for GET and POST requests
    # - Access-Control-Max-Age=20days, to minimize repetitive OPTIONS requests
    # - various superluous settings to accommodate nonconformant browsers
    #
    # == Comment on echoing Access-Control-Allow-Origin
    # 
    # How do you allow CORS requests only from certain domains? The last
    # published W3C candidate recommendation states that the
    # Access-Control-Allow-Origin header can include a list of origins.
    # (See: http://www.w3.org/TR/2013/CR-cors-20130129/#access-control-allow-origin-response-header )
    # However, browsers do not support this well and it likely will be
    # dropped from the spec (see, http://www.rfc-editor.org/errata_search.php?rfc=6454&eid=3249 ).
    # 
    # The usual workaround is for the server to keep a whitelist of
    # acceptable origins (as a regular expression), match the request's
    # Origin header against the list, and echo back the matched value.
    #
    # (Yes you can use '*' to accept all origins but this is too open and
    # prevents using 'Access-Control-Allow-Credentials: true', which is
    # needed for HTTP Basic Access authentication.)
    #
    # == Comment on  spec
    #
    # Comments below are all based on my reading of the CORS spec as of
    # 2013-Jan-29 ( http://www.w3.org/TR/2013/CR-cors-20130129/ ), the
    # XMLHttpRequest spec (
    # http://www.w3.org/TR/2012/WD-XMLHttpRequest-20121206/ ), and
    # experimentation with latest versions of Firefox, Chrome, Safari at
    # that point in time.
    #
    # == Changelog
    #
    # shared at: https://gist.github.com/algal/5480916
    # based on: https://gist.github.com/alexjs/4165271
    #
    
    location / {
    
        # if the request included an Origin: header with an origin on the whitelist,
        # then it is some kind of CORS request.
    
        # specifically, this example allow CORS requests from
        #  scheme    : http or https
        #  authority : any authority ending in ".mckinsey.com"
        #  port      : nothing, or :
        if ($http_origin ~* (https?://[^/]*.mckinsey.com(:[0-9]+)?)$) {
            set $cors "true";
        }
    
        # Nginx doesn't support nested If statements, so we use string
        # concatenation to create a flag for compound conditions
    
        # OPTIONS indicates a CORS pre-flight request
        if ($request_method = 'OPTIONS') {
            set $cors "${cors}options";  
        }
    
        # non-OPTIONS indicates a normal CORS request
        if ($request_method = 'GET') {
            set $cors "${cors}get";  
        }
        if ($request_method = 'POST') {
            set $cors "${cors}post";
        }
    
        # if it's a GET or POST, set the standard CORS responses header
        if ($cors = "trueget") {
            # Tells the browser this origin may make cross-origin requests
            # (Here, we echo the requesting origin, which matched the whitelist.)
            add_header 'Access-Control-Allow-Origin' "$http_origin";
            # Tells the browser it may show the response, when XmlHttpRequest.withCredentials=true.
            add_header 'Access-Control-Allow-Credentials' 'true';
            # # Tell the browser which response headers the JS can see, besides the "simple response headers"
            # add_header 'Access-Control-Expose-Headers' 'myresponseheader';
        }
    
        if ($cors = "truepost") {
            # Tells the browser this origin may make cross-origin requests
            # (Here, we echo the requesting origin, which matched the whitelist.)
            add_header 'Access-Control-Allow-Origin' "$http_origin";
            # Tells the browser it may show the response, when XmlHttpRequest.withCredentials=true.
            add_header 'Access-Control-Allow-Credentials' 'true';
            # # Tell the browser which response headers the JS can see, besides the "simple response headers"
            # add_header 'Access-Control-Expose-Headers' 'myresponseheader';
        }
    
        # if it's OPTIONS, then it's a CORS preflight request so respond immediately with no response body
        if ($cors = "trueoptions") {
            # Tells the browser this origin may make cross-origin requests
            # (Here, we echo the requesting origin, which matched the whitelist.)
            add_header 'Access-Control-Allow-Origin' "$http_origin";
            # in a preflight response, tells browser the subsequent actual request can include user credentials (e.g., cookies)
            add_header 'Access-Control-Allow-Credentials' 'true';
    
            #
            # Return special preflight info
            #
            
            # Tell browser to cache this pre-flight info for 20 days
            add_header 'Access-Control-Max-Age' 1728000;
    
            # Tell browser we respond to GET,POST,OPTIONS in normal CORS requests.
            #
            # Not officially needed but still included to help non-conforming browsers.
            #
            # OPTIONS should not be needed here, since the field is used
            # to indicate methods allowed for "actual request" not the
            # preflight request.
            #
            # GET,POST also should not be needed, since the "simple
            # methods" GET,POST,HEAD are included by default.
            #
            # We should only need this header for non-simple requests
            # methods (e.g., DELETE), or custom request methods (e.g., XMODIFY)
            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
            
            # Tell browser we accept these headers in the actual request
            #
            # A dynamic, wide-open config would just echo back all the headers
            # listed in the preflight request's
            # Access-Control-Request-Headers.
            #
            # A dynamic, restrictive config, would just echo back the
            # subset of Access-Control-Request-Headers headers which are
            # allowed for this resource.
            #
            # This static, fairly open config just returns a hardcoded set of
            # headers that covers many cases, including some headers that
            # are officially unnecessary but actually needed to support
            # non-conforming browsers
            # 
            # Comment on some particular headers below:
            #
            # Authorization -- practically and officially needed to support
            # requests using HTTP Basic Access authentication. Browser JS
            # can use HTTP BA authentication with an XmlHttpRequest object
            # req by calling
            # 
            #   req.withCredentials=true,  and
            #   req.setRequestHeader('Authorization','Basic ' + window.btoa(theusername + ':' + thepassword))
            #
            # Counterintuitively, the username and password fields on
            # XmlHttpRequest#open cannot be used to set the authorization
            # field automatically for CORS requests.
            #
            # Content-Type -- this is a "simple header" only when it's
            # value is either application/x-www-form-urlencoded,
            # multipart/form-data, or text/plain; and in that case it does
            # not officially need to be included. But, if your browser
            # code sets the content type as application/json, for example,
            # then that makes the header non-simple, and then your server
            # must declare that it allows the Content-Type header.
            # 
            # Accept,Accept-Language,Content-Language -- these are the
            # "simple headers" and they are officially never
            # required. Practically, possibly required.
            #
            # Origin -- logically, should not need to be explicitly
            # required, since it's implicitly required by all of
            # CORS. officially, it is unclear if it is required or
            # forbidden! practically, probably required by existing
            # browsers (Gecko does not request it but WebKit does, so
            # WebKit might choke if it's not returned back).
            #
            # User-Agent,DNT -- officially, should not be required, as
            # they cannot be set as "author request headers". practically,
            # may be required.
            # 
            # My Comment:
            #
            # The specs are contradictory, or else just confusing to me,
            # in how they describe certain headers as required by CORS but
            # forbidden by XmlHttpRequest. The CORS spec says the browser
            # is supposed to set Access-Control-Request-Headers to include
            # only "author request headers" (section 7.1.5). And then the
            # server is supposed to use Access-Control-Allow-Headers to
            # echo back the subset of those which is allowed, telling the
            # browser that it should not continue and perform the actual
            # request if it includes additional headers (section 7.1.5,
            # step 8). So this implies the browser client code must take
            # care to include all necessary headers as author request
            # headers.
            # 
            # However, the spec for XmlHttpRequest#setRequestHeader
            # (section 4.6.2) provides a long list of headers which the
            # the browser client code is forbidden to set, including for
            # instance Origin, DNT (do not track), User-Agent, etc.. This
            # is understandable: these are all headers that we want the
            # browser itself to control, so that malicious browser client
            # code cannot spoof them and for instance pretend to be from a
            # different origin, etc..
            #
            # But if XmlHttpRequest forbids the browser client code from
            # setting these (as per the XmlHttpRequest spec), then they
            # are not author request headers. And if they are not author
            # request headers, then the browser should not include them in
            # the preflight request's Access-Control-Request-Headers. And
            # if they are not included in Access-Control-Request-Headers,
            # then they should not be echoed by
            # Access-Control-Allow-Headers. And if they are not echoed by
            # Access-Control-Allow-Headers, then the browser should not
            # continue and execute actual request. So this seems to imply
            # that the CORS and XmlHttpRequest specs forbid certain
            # widely-used fields in CORS requests, including the Origin
            # field, which they also require for CORS requests.
            #
            # The bottom line: it seems there are headers needed for the
            # web and CORS to work, which at the moment you should
            # hard-code into Access-Control-Allow-Headers, although
            # official specs imply this should not be necessary.
            # 
            add_header 'Access-Control-Allow-Headers' 'Authorization,Content-Type,Accept,Origin,User-Agent,DNT,Cache-Control,X-Mx-ReqToken,Keep-Alive,X-Requested-With,If-Modified-Since';
    
            # build entire response to the preflight request
            # no body in this response
            add_header 'Content-Length' 0;
            # (should not be necessary, but included for non-conforming browsers)
            add_header 'Content-Type' 'text/plain charset=UTF-8';
            # indicate successful return with no content
            return 204;
        }
        # --PUT YOUR REGULAR NGINX CODE HERE--
    }
      

    server解析流程例如以下:

    a.首先查看http头部有无origin字段;

    b.假设没有,或者不同意,直接当成普通请求处理,结束;

    c.假设有而且是同意的。那么再看是否是preflight(method=OPTIONS);

    d.假设是preflight,就返回Allow-Headers、Allow-Methods等,内容为空;

    e.假设不是preflight。就返回Allow-Origin、Allow-Credentials等,并返回正常内容。

    若server为nginx。能够nginxconf文件里增加下面内容:

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

    若server为Apache,则能够依照例如以下配置:

    <IfModule mod_setenvif.c>
        <IfModule mod_headers.c>
            <FilesMatch ".(cur|gif|ico|jpe?g|png|svgz?|webp)$">
                SetEnvIf Origin ":" IS_CORS
                Header set Access-Control-Allow-Origin "*" env=IS_CORS
            </FilesMatch>
        </IfModule>
    </IfModule>
    

    为安全起见,Access-Control-Allow-Origin也可设为特定域名的方式。

    在HTML5中,有些HTML元素为CORS提供了支持,如img、video新增了crossOrigin属性。属性值能够为anonymoususe-credentials

    比方,canvas画图要用到跨域图片,在JavaScript中要设置img.crossOrigin="Anonymous";

     

    var img = new Image,
        canvas = document.createElement("canvas"),
        ctx = canvas.getContext("2d"),
        src = "http://example.com/image"; // insert image url here
    
    img.crossOrigin = "Anonymous";
    
    img.onload = function() {
        canvas.width = img.width;
        canvas.height = img.height;
        ctx.drawImage( img, 0, 0 );
        localStorage.setItem( "savedImageData", canvas.toDataURL("image/png") );
    }
    img.src = src;
    // make sure the load event fires for cached images too
    if ( img.complete || img.complete === undefined ) {
        img.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
        img.src = src;
    }
    

    上述配置完毕后,重新启动server。CORS启用。

    然后我们再刷新页面,查询请求头的參数,能够发现多出一个:Access-Control-Allow-Origin:*

    ,到此证明server配置已经生效。

    同一时候我们的canvas画图也能够正常使用了。

    刷新页面返回请求响应结果后,HTTP Request Headers的内容:

    Remote Address:222.132.18.xx:80

    Request URL:http://js.xx.com/static/activity/sq/guagua315/images/card_inner.jpg

    Request Method:GET

    Status Code:200 OK

    Request Headersview source

    Accept:image/webp,*/*;q=0.8

    Accept-Encoding:gzip, deflate, sdch

    Accept-Language:zh-CN,zh;q=0.8

    Cache-Control:no-cache

    Connection:keep-alive

    Host:js.xx.com

    Origin:http://act.xx.com

    Pragma:no-cache

    RA-Sid:7CCAD53E-20140704-054839-03c57a-85faf2

    RA-Ver:2.8.8

    Referer:http://act.xx.com/sq/guagua315?

    uuid=46124642&fid=2&sign=xxx

    User-Agent:Mozilla/5.0 (Windows NT 6.1;WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.115Safari/537.36

    Response Headersview source

    Accept-Ranges:bytes

    Access-Control-Allow-Origin:*

    Connection:close

    Content-Length:4010

    Content-Type:image/jpeg

    Date:Thu, 12 Mar 2015 02:29:43 GMT

    ETag:"54f7d1b4-faa"

    Last-Modified:Thu, 05 Mar 2015 03:47:00 GMT

    Powered-By-ChinaCache:MISS fromCNC-WF-3-3X6

    Powered-By-ChinaCache:MISS fromCNC-WF-3-3X5

    Server:Tengine

    Switch:FSCS

    附图:


    參考文章:

    CORS enabled image  https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_image

    CORS on Nginx   http://enable-cors.org/server_nginx.html

    Nginx CORS实现JS跨域  http://blog.csdn.net/oyzl68/article/details/18741057

    转载请注明出处。文章来自于freshlover的CSDN空间《Ajax跨域、Json跨域、Socket跨域和Canvas跨域等同源策略限制的解决方法》 

    http://blog.csdn.net/freshlover/article/details/44223467


  • 相关阅读:
    我的python中级班学习之路(全程笔记第一模块) (第一章)语言基础
    Python_常用模块
    Python_装饰器、迭代器、生成器
    Python_函数
    Python_深浅拷贝
    Python_文件操作
    Python_三级目录
    Python_循环判断表达式
    Python_基础语法
    7段数码管绘制
  • 原文地址:https://www.cnblogs.com/gavanwanggw/p/6857699.html
Copyright © 2011-2022 走看看