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

Ajax跨域、Json跨域、Socket跨域和Canvas跨域等同源策略限制的解決方法 分類: 前端開發 2015-03-12 16:53 6267人閱讀 評論(0) 收藏 舉報 cross-originCanvas跨域圖片跨域JSON跨域Ajax跨域

同源是指相同的協議、域名、埠,三者都相同才屬於同域。不符合上述定義的請求,則稱為跨域。

相信每個開發人員都曾遇到過跨域請求的情況,雖然情況不一樣,但問題的本質都可以歸為瀏覽器出於安全考慮下的同源策略的限制。

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

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=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)修改伺服器配置啟用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。代碼:

[plain] view plaincopy

  1. #
  2. #ACORS(Cross-OriginResouceSharing)configfornginx
  3. #
  4. #==Purpose
  5. #
  6. #ThisnginxconfigurationenablesCORSrequestsinthefollowingway:
  7. #-enablesCORSjustfororiginsonawhitelistspecifiedbyaregular
  8. #-CORSpreflightrequest(OPTIONS)arerespondedimmediately
  9. #-Access-Control-Allow-Credentials=trueforGETandPOSTrequests
  10. #-Access-Control-Max-Age=20days,tominimizerepetitiveOPTIONSrequests
  11. #-varioussuperluoussettingstoaccommodatenonconformantbrowsers
  12. #
  13. #==CommentonechoingAccess-Control-Allow-Origin
  14. #
  15. #HowdoyouallowCORSrequestsonlyfromcertaindomains?Thelast
  16. #publishedW3Ccandidaterecommendationstatesthatthe
  17. #Access-Control-Allow-Originheadercanincludealistoforigins.
  18. #(See:http://www.w3.org/TR/2013/CR-cors-20130129/#access-control-allow-origin-response-header)
  19. #However,browsersdonotsupportthiswellanditlikelywillbe
  20. #droppedfromthespec(see,http://www.rfc-editor.org/errata_search.php?rfc=6454&eid=3249).
  21. #
  22. #Theusualworkaroundisfortheservertokeepawhitelistof
  23. #acceptableorigins(asaregular),matchtherequest"s
  24. #Originheaderagainstthelist,andechobackthematchedvalue.
  25. #
  26. #(Yesyoucanuse"*"toacceptalloriginsbutthisistooopenand
  27. #preventsusing"Access-Control-Allow-Credentials:true",whichis
  28. #neededforHTTPBasicAccessauthentication.)
  29. #
  30. #==Commentonspec
  31. #
  32. #CommentsbelowareallbasedonmyreadingoftheCORSspecasof
  33. #2013-Jan-29(http://www.w3.org/TR/2013/CR-cors-20130129/),the
  34. #XMLHttpRequestspec(
  35. #http://www.w3.org/TR/2012/WD-XMLHttpRequest-20121206/),and
  36. #experimentationwithlatestversionsofFirefox,Chrome,Safariat
  37. #thatpointintime.
  38. #
  39. #==Changelog
  40. #
  41. #sharedat:https://gist.github.com/algal/5480916
  42. #basedon:https://gist.github.com/alexjs/4165271
  43. #
  44. location/{
  45. #iftherequestincludedanOrigin:headerwithanoriginonthewhitelist,
  46. #thenitissomekindofCORSrequest.
  47. #specifically,thisexampleallowCORSrequestsfrom
  48. #scheme:httporhttps
  49. #authority:anyauthorityendingin".mckinsey.com"
  50. #port:nothing,or:
  51. if($http_origin~*(https?://[^/]*.mckinsey.com(:[0-9]+)?)$){
  52. set$cors"true";
  53. }
  54. #Nginxdoesn"tsupportnestedIfstatements,soweusestring
  55. #concatenationtocreateaflagforcompoundconditions
  56. #OPTIONSindicatesaCORSpre-flightrequest
  57. if($request_method="OPTIONS"){
  58. set$cors"${cors}options";
  59. }
  60. #non-OPTIONSindicatesanormalCORSrequest
  61. if($request_method="GET"){
  62. set$cors"${cors}get";
  63. }
  64. if($request_method="POST"){
  65. set$cors"${cors}post";
  66. }
  67. #ifit"saGETorPOST,setthestandardCORSresponsesheader
  68. if($cors="trueget"){
  69. #Tellsthebrowserthisoriginmaymakecross-originrequests
  70. #(Here,weechotherequestingorigin,whichmatchedthewhitelist.)
  71. add_header"Access-Control-Allow-Origin""$http_origin";
  72. #Tellsthebrowseritmayshowtheresponse,whenXmlHttpRequest.withCredentials=true.
  73. add_header"Access-Control-Allow-Credentials""true";
  74. ##TellthebrowserwhichresponseheaderstheJScansee,besidesthe"simpleresponseheaders"
  75. #add_header"Access-Control-Expose-Headers""myresponseheader";
  76. }
  77. if($cors="truepost"){
  78. #Tellsthebrowserthisoriginmaymakecross-originrequests
  79. #(Here,weechotherequestingorigin,whichmatchedthewhitelist.)
  80. add_header"Access-Control-Allow-Origin""$http_origin";
  81. #Tellsthebrowseritmayshowtheresponse,whenXmlHttpRequest.withCredentials=true.
  82. add_header"Access-Control-Allow-Credentials""true";
  83. ##TellthebrowserwhichresponseheaderstheJScansee,besidesthe"simpleresponseheaders"
  84. #add_header"Access-Control-Expose-Headers""myresponseheader";
  85. }
  86. #ifit"sOPTIONS,thenit"saCORSpreflightrequestsorespondimmediatelywithnoresponsebody
  87. if($cors="trueoptions"){
  88. #Tellsthebrowserthisoriginmaymakecross-originrequests
  89. #(Here,weechotherequestingorigin,whichmatchedthewhitelist.)
  90. add_header"Access-Control-Allow-Origin""$http_origin";
  91. #inapreflightresponse,tellsbrowserthesubsequentactualrequestcanincludeusercredentials(e.g.,cookies)
  92. add_header"Access-Control-Allow-Credentials""true";
  93. #
  94. #Returnspecialpreflightinfo
  95. #
  96. #Tellbrowsertocachethispre-flightinfofor20days
  97. add_header"Access-Control-Max-Age"1728000;
  98. #TellbrowserwerespondtoGET,POST,OPTIONSinnormalCORSrequests.
  99. #
  100. #Notofficiallyneededbutstillincludedtohelpnon-conformingbrowsers.
  101. #
  102. #OPTIONSshouldnotbeneededhere,sincethefieldisused
  103. #toindicatemethodsallowedfor"actualrequest"notthe
  104. #preflightrequest.
  105. #
  106. #GET,POSTalsoshouldnotbeneeded,sincethe"simple
  107. #methods"GET,POST,HEADareincludedbydefault.
  108. #
  109. #Weshouldonlyneedthisheaderfornon-simplerequests
  110. #methods(e.g.,DELETE),orcustomrequestmethods(e.g.,XMODIFY)
  111. add_header"Access-Control-Allow-Methods""GET,POST,OPTIONS";
  112. #Tellbrowserweaccepttheseheadersintheactualrequest
  113. #
  114. #Adynamic,wide-openconfigwouldjustechobackalltheheaders
  115. #listedinthepreflightrequest"s
  116. #Access-Control-Request-Headers.
  117. #
  118. #Adynamic,restrictiveconfig,wouldjustechobackthe
  119. #subsetofAccess-Control-Request-Headersheaderswhichare
  120. #allowedforthisresource.
  121. #
  122. #Thisstatic,fairlyopenconfigjustreturnsahardcodedsetof
  123. #headersthatcoversmanycases,includingsomeheadersthat
  124. #areofficiallyunnecessarybutactuallyneededtosupport
  125. #non-conformingbrowsers
  126. #
  127. #Commentonsomeparticularheadersbelow:
  128. #
  129. #Authorization--practicallyandofficiallyneededtosupport
  130. #requestsusingHTTPBasicAccessauthentication.BrowserJS
  131. #canuseHTTPBAauthenticationwithanXmlHttpRequestobject
  132. #reqbycalling
  133. #
  134. #req.withCredentials=true,and
  135. #req.setRequestHeader("Authorization","Basic"+window.btoa(theusername+":"+thepassword))
  136. #
  137. #Counterintuitively,theusernameandpasswordfieldson
  138. #XmlHttpRequest#opencannotbeusedtosettheauthorization
  139. #fieldautomaticallyforCORSrequests.
  140. #
  141. #Content-Type--thisisa"simpleheader"onlywhenit"s
  142. #valueiseitherapplication/x-www-form-urlencoded,
  143. #multipart/form-data,ortext/plain;andinthatcaseitdoes
  144. #notofficiallyneedtobeincluded.But,ifyourbrowser
  145. #codesetsthecontenttypeasapplication/json,forexample,
  146. #thenthatmakestheheadernon-simple,andthenyourserver
  147. #mustdeclarethatitallowstheContent-Typeheader.
  148. #
  149. #Accept,Accept-Language,Content-Language--thesearethe
  150. #"simpleheaders"andtheyareofficiallynever
  151. #required.Practically,possiblyrequired.
  152. #
  153. #Origin--logically,shouldnotneedtobeexplicitly
  154. #required,sinceit"simplicitlyrequiredbyallof
  155. #CORS.officially,itisunclearifitisrequiredor
  156. #forbidden!practically,probablyrequiredbyexisting
  157. #browsers(GeckodoesnotrequestitbutWebKitdoes,so
  158. #WebKitmightchokeifit"snotreturnedback).
  159. #
  160. #User-Agent,DNT--officially,shouldnotberequired,as
  161. #theycannotbesetas"authorrequestheaders".practically,
  162. #mayberequired.
  163. #
  164. #MyComment:
  165. #
  166. #Thespecsarecontradictory,orelsejustconfusingtome,
  167. #inhowtheydescribecertainheadersasrequiredbyCORSbut
  168. #forbiddenbyXmlHttpRequest.TheCORSspecsaysthebrowser
  169. #issupposedtosetAccess-Control-Request-Headerstoinclude
  170. #only"authorrequestheaders"(section7.1.5).Andthenthe
  171. #serverissupposedtouseAccess-Control-Allow-Headersto
  172. #echobackthesubsetofthosewhichisallowed,tellingthe
  173. #browserthatitshouldnotcontinueandperformtheactual
  174. #requestifitincludesadditionalheaders(section7.1.5,
  175. #step8).Sothisimpliesthebrowserclientcodemusttake
  176. #caretoincludeallnecessaryheadersasauthorrequest
  177. #headers.
  178. #
  179. #However,thespecforXmlHttpRequest#setRequestHeader
  180. #(section4.6.2)providesalonglistofheaderswhichthe
  181. #thebrowserclientcodeisforbiddentoset,includingfor
  182. #instanceOrigin,DNT(donottrack),User-Agent,etc..This
  183. #isunderstandable:theseareallheadersthatwewantthe
  184. #browseritselftocontrol,sothatmaliciousbrowserclient
  185. #codecannotspoofthemandforinstancepretendtobefroma
  186. #differentorigin,etc..
  187. #
  188. #ButifXmlHttpRequestforbidsthebrowserclientcodefrom
  189. #settingthese(aspertheXmlHttpRequestspec),thenthey
  190. #arenotauthorrequestheaders.Andiftheyarenotauthor
  191. #requestheaders,thenthebrowsershouldnotincludethemin
  192. #thepreflightrequest"sAccess-Control-Request-Headers.And
  193. #iftheyarenotincludedinAccess-Control-Request-Headers,
  194. #thentheyshouldnotbeechoedby
  195. #Access-Control-Allow-Headers.Andiftheyarenotechoedby
  196. #Access-Control-Allow-Headers,thenthebrowsershouldnot
  197. #continueandexecuteactualrequest.Sothisseemstoimply
  198. #thattheCORSandXmlHttpRequestspecsforbidcertain
  199. #widely-usedfieldsinCORSrequests,includingtheOrigin
  200. #field,whichtheyalsorequireforCORSrequests.
  201. #
  202. #Thebottomline:itseemsthereareheadersneededforthe
  203. #webandCORStowork,whichatthemomentyoushould
  204. #hard-codeintoAccess-Control-Allow-Headers,although
  205. #officialspecsimplythisshouldnotbenecessary.
  206. #
  207. 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";
  208. #buildentireresponsetothepreflightrequest
  209. #nobodyinthisresponse
  210. add_header"Content-Length"0;
  211. #(shouldnotbenecessary,butincludedfornon-conformingbrowsers)
  212. add_header"Content-Type""text/plaincharset=UTF-8";
  213. #indicatesuccessfulreturnwithnocontent
  214. return204;
  215. }
  216. #--PUTYOURREGULARNGINXCODEHERE--
  217. }

伺服器解析流程如下:

a.首先查看http頭部有無origin欄位;

b.如果沒有,或者不允許,直接當成普通請求處理,結束;

c.如果有並且是允許的,那麼再看是否是preflight(method=OPTIONS);

d.如果是preflight,就返回Allow-Headers、Allow-Methods等,內容為空;

e.如果不是preflight,就返回Allow-Origin、Allow-Credentials等,並返回正常內容。

若伺服器為nginx,可以在nginx的conf文件中加入以下內容:[plain] view plaincopy

  1. location/{
  2. add_headerAccess-Control-Allow-Origin*;
  3. }

若伺服器為Apache,則可以按照如下配置:

[plain] view plaincopy

  1. <IfModulemod_setenvif.c>
  2. <IfModulemod_headers.c>
  3. <FilesMatch".(cur|gif|ico|jpe?g|png|svgz?|webp)$">
  4. SetEnvIfOrigin":"IS_CORS
  5. HeadersetAccess-Control-Allow-Origin"*"env=IS_CORS
  6. </FilesMatch>
  7. </IfModule>
  8. </IfModule>

為安全起見,Access-Control-Allow-Origin也可設為特定域名的方式。

在HTML5中,有些HTML元素為CORS提供了支持,如img、video新增了crossOrigin屬性,屬性值可以為anonymous或use-credentials。比如,canvas繪圖要用到跨域圖片,在JavaScript中要設置img.crossOrigin="Anonymous";

[javascript] view plaincopy

  1. varimg=newImage,
  2. canvas=document.createElement("canvas"),
  3. ctx=canvas.getContext("2d"),
  4. src="https://www.getit01.com/getimg_360.php?url=http://example.com/image";//insertimageurlhere
  5. img.crossOrigin="Anonymous";
  6. img.onload=function(){
  7. canvas.width_=img.width;
  8. canvas.height=img.height;
  9. ctx.drawImage(img,0,0);
  10. localStorage.setItem("savedImageData",canvas.toDataURL("image/png"));
  11. }
  12. img.src=src;
  13. //makesuretheloadeventfiresforcachedimagestoo
  14. if(img.complete||img.complete===undefined){
  15. img.src_="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
  16. img.src=src;
  17. }

上述配置完成後,重啟伺服器,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

附圖:

參考文章:

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

版權聲明:本文為博主原創文章,未經博主允許不得轉載。


推薦閱讀:

vue-schart : vue.js 的圖表組件
SpriteJS -- 一款簡單的跨終端 canvas 繪圖框架
canvas基礎繪製之時鐘
【canvas】一個少女心滿滿的例子帶你入門 canvas
小白記Canvas實現的一個小玩意 - 你的名字頭像生成

TAG:策略 | Socket | 方法 | 解決方法 | 限制 | Canvas | Ajax | 跨域 |