加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

Ajax跨域、Json跨域、Socket跨域和Canvas跨域等同源策略限制的解

发布时间:2020-12-15 21:43:36 所属栏目:百科 来源:网络整理
导读:同源是指相同的协议、域名、端口,三者都相同才属于同域。不符合上述定义的请求,则称为跨域。 相信每个开发人员都曾遇到过跨域请求的情况,虽然情况不一样,但问题的本质都可以归为浏览器出于安全考虑下的同源策略的限制。 跨域的情形有很多,最常见的有Aja

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

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

跨域的情形有很多,最常见的有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.

20150314114525602.png

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

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,附图如下

20150314114625319.png

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

附图:

20150314114626664.png

  • 本文来自:Linux教程网

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读