Ajax跨域、Json跨域、Socket跨域和Canvas跨域等同源策略限制的解
同源是指相同的协议、域名、端口,三者都相同才属于同域。不符合上述定义的请求,则称为跨域。 相信每个开发人员都曾遇到过跨域请求的情况,虽然情况不一样,但问题的本质都可以归为浏览器出于安全考虑下的同源策略的限制。 跨域的情形有很多,最常见的有Ajax跨域、Socket跨域和Canvas跨域。下面列举一些我们常见的跨域情形下,某些浏览器控制台给出的错误提示: FireFox下的提示: 已阻止交叉源请求:同源策略不允许读取***上的远程资源。可以将资源移动到相同的域名上或者启用 CORS 来解决这个问题。 Canvas跨域Chrome下的提示: Uncaught SecurityError : Failed to execute 'getImageData' on 'CanvasRenderingContext2D' : The canvas has been tainted by 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 width:283, height:154, //color: "#a9a9a7", image2:"imgdata.php?url=http://js.xxx.com/static/activity/sq/guagua315/images/card_inner.jpg", scratchMove:function() { } }); 或: xi= new XMLHttpRequest (); xi.open( "GET","imgdata.php?url=" +yourImageURL,true ); xi.send(); xi.onreadystatechange= function () { if (xi.readyState== 4 && xi.status== 200 ) { img= new Image ; img. function (){ ctx.drawImage(img,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: Header Value'); 这样的header标记: header('Access-Control-Allow-Origin:*'); 4)修改服务器配置启用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应答。所以服务器必须处理OPTIONS应答。 这里是一个nginx启用CORS的参考配置示例http://enable-cors.org/server_nginx.html。代码: # #ACORS(Cross-OriginResouceSharing)configfornginx # #==Purpose # #ThisnginxconfigurationenablesCORSrequestsinthefollowingway: #-enablesCORSjustfororiginsonawhitelistspecifiedbyaregularexpression #-CORSpreflightrequest(OPTIONS)arerespondedimmediately #-Access-Control-Allow-Credentials=trueforGETandPOSTrequests #-Access-Control-Max-Age=20days,tominimizerepetitiveOPTIONSrequests #-varioussuperluoussettingstoaccommodatenonconformantbrowsers # #==CommentonechoingAccess-Control-Allow-Origin # #HowdoyouallowCORSrequestsonlyfromcertaindomains?Thelast #publishedW3Ccandidaterecommendationstatesthatthe #Access-Control-Allow-Originheadercanincludealistoforigins. #(See:http://www.w3.org/TR/2013/CR-cors-20130129/#access-control-allow-origin-response-header) #However,browsersdonotsupportthiswellanditlikelywillbe #droppedfromthespec(see,http://www.rfc-editor.org/errata_search.php?rfc=6454&eid=3249). # #Theusualworkaroundisfortheservertokeepawhitelistof #acceptableorigins(asaregularexpression),matchtherequest's #Originheaderagainstthelist,andechobackthematchedvalue. # #(Yesyoucanuse'*'toacceptalloriginsbutthisistooopenand #preventsusing'Access-Control-Allow-Credentials:true',whichis #neededforHTTPBasicAccessauthentication.) # #==Commentonspec # #CommentsbelowareallbasedonmyreadingoftheCORSspecasof #2013-Jan-29(http://www.w3.org/TR/2013/CR-cors-20130129/),the #XMLHttpRequestspec( #http://www.w3.org/TR/2012/WD-XMLHttpRequest-20121206/),and #experimentationwithlatestversionsofFirefox,Chrome,Safariat #thatpointintime. # #==Changelog # #sharedat:https://gist.github.com/algal/5480916 #basedon:https://gist.github.com/alexjs/4165271 # location/{ #iftherequestincludedanOrigin:headerwithanoriginonthewhitelist,#thenitissomekindofCORSrequest. #specifically,thisexampleallowCORSrequestsfrom #scheme:httporhttps #authority:anyauthorityendingin".mckinsey.com" #port:nothing,or: if($http_origin~*(https?://[^/]*.mckinsey.com(:[0-9]+)?)$){ set$cors"true"; } #Nginxdoesn'tsupportnestedIfstatements,soweusestring #concatenationtocreateaflagforcompoundconditions #OPTIONSindicatesaCORSpre-flightrequest if($request_method='OPTIONS'){ set$cors"${cors}options"; } #non-OPTIONSindicatesanormalCORSrequest if($request_method='GET'){ set$cors"${cors}get"; } if($request_method='POST'){ set$cors"${cors}post"; } #ifit'saGETorPOST,setthestandardCORSresponsesheader if($cors="trueget"){ #Tellsthebrowserthisoriginmaymakecross-originrequests #(Here,weechotherequestingorigin,whichmatchedthewhitelist.) add_header'Access-Control-Allow-Origin'"$http_origin"; #Tellsthebrowseritmayshowtheresponse,whenXmlHttpRequest.withCredentials=true. add_header'Access-Control-Allow-Credentials''true'; ##TellthebrowserwhichresponseheaderstheJScansee,besidesthe"simpleresponseheaders" #add_header'Access-Control-Expose-Headers''myresponseheader'; } if($cors="truepost"){ #Tellsthebrowserthisoriginmaymakecross-originrequests #(Here,besidesthe"simpleresponseheaders" #add_header'Access-Control-Expose-Headers''myresponseheader'; } #ifit'sOPTIONS,thenit'saCORSpreflightrequestsorespondimmediatelywithnoresponsebody if($cors="trueoptions"){ #Tellsthebrowserthisoriginmaymakecross-originrequests #(Here,whichmatchedthewhitelist.) add_header'Access-Control-Allow-Origin'"$http_origin"; #inapreflightresponse,tellsbrowserthesubsequentactualrequestcanincludeusercredentials(e.g.,cookies) add_header'Access-Control-Allow-Credentials''true'; # #Returnspecialpreflightinfo # #Tellbrowsertocachethispre-flightinfofor20days add_header'Access-Control-Max-Age'1728000; #TellbrowserwerespondtoGET,POST,OPTIONSinnormalCORSrequests. # #Notofficiallyneededbutstillincludedtohelpnon-conformingbrowsers. # #OPTIONSshouldnotbeneededhere,sincethefieldisused #toindicatemethodsallowedfor"actualrequest"notthe #preflightrequest. # #GET,POSTalsoshouldnotbeneeded,sincethe"simple #methods"GET,HEADareincludedbydefault. # #Weshouldonlyneedthisheaderfornon-simplerequests #methods(e.g.,DELETE),orcustomrequestmethods(e.g.,XMODIFY) add_header'Access-Control-Allow-Methods''GET,OPTIONS'; #Tellbrowserweaccepttheseheadersintheactualrequest # #Adynamic,wide-openconfigwouldjustechobackalltheheaders #listedinthepreflightrequest's #Access-Control-Request-Headers. # #Adynamic,restrictiveconfig,wouldjustechobackthe #subsetofAccess-Control-Request-Headersheaderswhichare #allowedforthisresource. # #Thisstatic,fairlyopenconfigjustreturnsahardcodedsetof #headersthatcoversmanycases,includingsomeheadersthat #areofficiallyunnecessarybutactuallyneededtosupport #non-conformingbrowsers # #Commentonsomeparticularheadersbelow: # #Authorization--practicallyandofficiallyneededtosupport #requestsusingHTTPBasicAccessauthentication.BrowserJS #canuseHTTPBAauthenticationwithanXmlHttpRequestobject #reqbycalling # #req.withCredentials=true,and #req.setRequestHeader('Authorization','Basic'+window.btoa(theusername+':'+thepassword)) # #Counterintuitively,theusernameandpasswordfieldson #XmlHttpRequest#opencannotbeusedtosettheauthorization #fieldautomaticallyforCORSrequests. # #Content-Type--thisisa"simpleheader"onlywhenit's #valueiseitherapplication/x-www-form-urlencoded,#multipart/form-data,ortext/plain;andinthatcaseitdoes #notofficiallyneedtobeincluded.But,ifyourbrowser #codesetsthecontenttypeasapplication/json,forexample,#thenthatmakestheheadernon-simple,andthenyourserver #mustdeclarethatitallowstheContent-Typeheader. # #Accept,Accept-Language,Content-Language--thesearethe #"simpleheaders"andtheyareofficiallynever #required.Practically,possiblyrequired. # #Origin--logically,shouldnotneedtobeexplicitly #required,sinceit'simplicitlyrequiredbyallof #CORS.officially,itisunclearifitisrequiredor #forbidden!practically,probablyrequiredbyexisting #browsers(GeckodoesnotrequestitbutWebKitdoes,so #WebKitmightchokeifit'snotreturnedback). # #User-Agent,DNT--officially,shouldnotberequired,as #theycannotbesetas"authorrequestheaders".practically,#mayberequired. # #MyComment: # #Thespecsarecontradictory,orelsejustconfusingtome,#inhowtheydescribecertainheadersasrequiredbyCORSbut #forbiddenbyXmlHttpRequest.TheCORSspecsaysthebrowser #issupposedtosetAccess-Control-Request-Headerstoinclude #only"authorrequestheaders"(section7.1.5).Andthenthe #serverissupposedtouseAccess-Control-Allow-Headersto #echobackthesubsetofthosewhichisallowed,tellingthe #browserthatitshouldnotcontinueandperformtheactual #requestifitincludesadditionalheaders(section7.1.5,#step8).Sothisimpliesthebrowserclientcodemusttake #caretoincludeallnecessaryheadersasauthorrequest #headers. # #However,thespecforXmlHttpRequest#setRequestHeader #(section4.6.2)providesalonglistofheaderswhichthe #thebrowserclientcodeisforbiddentoset,includingfor #instanceOrigin,DNT(donottrack),User-Agent,etc..This #isunderstandable:theseareallheadersthatwewantthe #browseritselftocontrol,sothatmaliciousbrowserclient #codecannotspoofthemandforinstancepretendtobefroma #differentorigin,etc.. # #ButifXmlHttpRequestforbidsthebrowserclientcodefrom #settingthese(aspertheXmlHttpRequestspec),thenthey #arenotauthorrequestheaders.Andiftheyarenotauthor #requestheaders,thenthebrowsershouldnotincludethemin #thepreflightrequest'sAccess-Control-Request-Headers.And #iftheyarenotincludedinAccess-Control-Request-Headers,#thentheyshouldnotbeechoedby #Access-Control-Allow-Headers.Andiftheyarenotechoedby #Access-Control-Allow-Headers,thenthebrowsershouldnot #continueandexecuteactualrequest.Sothisseemstoimply #thattheCORSandXmlHttpRequestspecsforbidcertain #widely-usedfieldsinCORSrequests,includingtheOrigin #field,whichtheyalsorequireforCORSrequests. # #Thebottomline:itseemsthereareheadersneededforthe #webandCORStowork,whichatthemomentyoushould #hard-codeintoAccess-Control-Allow-Headers,although #officialspecsimplythisshouldnotbenecessary. # add_header'Access-Control-Allow-Headers''Authorization,Content-Type,Accept,Origin,DNT,Cache-Control,X-Mx-ReqToken,Keep-Alive,X-Requested-With,If-Modified-Since'; #buildentireresponsetothepreflightrequest #nobodyinthisresponse add_header'Content-Length'0; #(shouldnotbenecessary,butincludedfornon-conformingbrowsers) add_header'Content-Type''text/plaincharset=UTF-8'; #indicatesuccessfulreturnwithnocontent return204; } #--PUTYOURREGULARNGINXCODEHERE-- } 服务器解析流程如下: a.首先查看http头部有无origin字段; b.如果没有,或者不允许,直接当成普通请求处理,结束; c.如果有并且是允许的,那么再看是否是preflight(method=OPTIONS); d.如果是preflight,就返回Allow-Headers、Allow-Methods等,内容为空; e.如果不是preflight,就返回Allow-Origin、Allow-Credentials等,并返回正常内容。 若服务器为nginx,可以 在 nginx 的 conf 文件中加入以下内容: location/{ add_headerAccess-Control-Allow-Origin*; } 若服务器为Apache,则可以按照如下配置: <IfModulemod_setenvif.c> <IfModulemod_headers.c> <FilesMatch".(cur|gif|ico|jpe?g|png|svgz?|webp)$"> SetEnvIfOrigin":"IS_CORS HeadersetAccess-Control-Allow-Origin"*"env=IS_CORS </FilesMatch> </IfModule> </IfModule> 为安全起见,Access-Control-Allow-Origin也可设为特定域名的方式。 在HTML5中,有些HTML元素为CORS提供了支持,如img、video新增了 crossOrigin 属性,属性值可以为 anonymous 或 use-credentials 。比如, canvas 绘图要用到跨域图片,在 JavaScript 中要设置 img . crossOrigin = "Anonymous" ; varimg=newImage,canvas=document.createElement("canvas"),ctx=canvas.getContext("2d"),src="http://example.com/image";//insertimageurlhere img.crossOrigin="Anonymous"; img.onload=function(){ canvas.width=img.width; canvas.height=img.height; ctx.drawImage(img,0); localStorage.setItem("savedImageData",canvas.toDataURL("image/png")); } img.src=src; //makesuretheloadeventfiresforcachedimagestoo if(img.complete||img.complete===undefined){ img.src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw=="; img.src=src; } 上述配置完成后,重启服务器,CORS启用。 然后我们再刷新页面,查询请求头的参数,可以发现多出一个:Access-Control-Allow-Origin:* ,到此证明服务器配置已经生效。同时我们的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 附图:
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- ruby-on-rails – 用于动态页面的Rails嵌套路由
- 使用C#的ASP .NET中的数组键值
- C#和VB6:如何将’with’语句转换为C#?
- ruby-on-rails – 将HAML与RSPEC集成
- flex_菜单浅析;
- ArcGIS API for Flex3实现Query查询定位功能
- Jmeter-使用正则表达式提取器获取关联参数
- 如何通过Flex / actionscript中的属性名/值来查找特定的xml
- Client found response content type of 'multipart/re
- JNI出现无法找到依赖库的问题汇总(1)——Can't find de