因爲 Javascript 同源策略的存在使得一個源中加載來自其它源中資源的行爲受到了限制。即會出現跨域請求禁止。html
通俗一點說就是若是存在協議、域名、端口或者子域名不一樣服務端,或一者爲IP地址,一者爲域名地址(在跨域問題上,域僅僅是經過「 url的首部 」來識別而不會去嘗試判斷相同的IP地址對應着兩個域或者兩個域是否同屬同一個IP),之中任意服務端旗下的客戶端發起請求其它服務端資源的訪問行動都是跨域的,而瀏覽器爲了安全問題通常都限制了跨域訪問,也就是不容許跨域請求資源。前端
但不少時候咱們卻又不得不去跨域請求資源,這個時候就須要咱們想方法去繞過瀏覽器同源策略的限制了。html5
常見的跨域請求解決方法:shell
1.Jsonp 利用script標籤發起get請求不會出現跨域禁止的特色實現json
2.window.name+iframe 藉助中介屬性window.name實現跨域
3.html5的 postMessage 主要側重於前端通信,不一樣域下頁面之間的數據傳遞瀏覽器
4.Cors須要服務器設置header:Access-Control-Allow-Origin
安全
5.Nginx反向代理 能夠不須要目標服務器配合,不過須要Nginx中轉服務器,用於轉發請求(服務端之間的資源請求不會有跨域限制)服務器
下面分別說一下經常使用幾種解決方案的具體實現:cors
1 Jsonp
通常狀況下因爲同源策略咱們不可以經過XHR跨域去請求資源,可是咱們的script標籤卻能夠不受此限制成功的外鏈到來自於其餘域下的資源。利用script標籤這個特色,咱們能夠成功的繞過同源策略。但這種方式存在侷限性,咱們只可以發起get跨域請求。具體實現:
客戶端
服務端
script標籤跨域發起get請求,同時傳遞在客戶端已經註冊的全局函數 process_fun 做爲查詢參數,服務端代碼提取查詢參數,並傳入須要返回的數據。script標籤還有一個特色,就是會當即執行調用所請求到的資源,因此這個時候服務端返回的 process_fun(data) 這一句代碼會被當即執行,即把數據 data 傳入咱們事先定義好的函數 process_fun 中執行進一步的處理。
2 Cors
即跨域資源共享。實現cors通訊的關鍵是服務器,只要服務器實現了cors接口,就能夠跨源通訊。不過不一樣於jsonp,cors對於IE8如下的瀏覽器是不支持的。
客戶端
服務端
跨域資源共享在我看來是最直接也最簡便的解決跨域問題的方式了,惟一的缺陷也就只是不能覆蓋支持全部的瀏覽器。客戶端不須要去作另外的改變,跟通常情況下發送的異步請求一致就行,甚至客戶端根本不須要知道所請求的接口是跨域的。而服務端所須要作的也只是返回響應的同時設置 Access-Control-Allow-Origin
響應頭部,意爲「予許指定源(‘*’爲任意源)發起跨域資源請求」。
3 window.name 和 postMessage
window.name 和 postMessage 主要都側重於純前端頁面之間的數據通信,前者利用了 「 在同一瀏覽器窗口載入的不一樣頁面( 不管它們是否不一樣域 ),共享同一個window.name,而且都對 window.name 有讀寫的權限 」 的這一特性來實現頁面間的數據交換,後者則是HTML5的API,不一樣域下的頁面在知足必定關係的條件下能夠經過此API跨域傳送數據。
4 Nginx反向代理
Nginx反向代理解決跨域問題則是利用了服務端之間的資源請求不會有跨域限制的特色實現的,具體來講就是咱們前端發起的請求被Nginx攔截,再由Nginx代由轉發請求到資源服務器請求資源。
好比如今咱們有兩個Nodejs服務,分別是http://127.0.0.1:3000 和 http://127.0.0.1:5000,5000端口對應的服務端下的頁面須要發起請求3000端口所對應的服務端的資源,固然,在這種狀況下若是不作任何的額外處理,請求會產生跨域。這個時候咱們能夠用Nginx來代理轉發咱們的請求,前端不去直接對資源服務器發起請求,而是改成直接訪問Nginx服務器,看到這裏你可能會問了,發起請求的前端頁面是屬於 http://127.0.0.1:5000 所在域下的,對Nginx服務發起請求難道不會和以前直接發起的請求同樣出現跨域嗎?因此這裏須要明白的一點是,一開始咱們多是經過 http://127.0.0.1:5000/ 這樣的路徑訪問到咱們的頁面的,可是若是咱們使用Nginx做爲反向代理,代理服務器監聽8080端口,咱們這時候再訪問該頁面就再也不是訪問 http://127.0.0.1:5000/ , 而是 http://127.0.0.1:8080/ 了,在Nginx中咱們再作這樣的配置:
location / { proxy_pass http://127.0.0.1:5000; }
就能成功訪問到首頁了,而這個時候首頁是在 8080 端口所對應的域下(即Nginx服務)被渲染出來的,因此首頁這個時候便再也不與 http://127.0.0.1:5000 同域, 而是與 Nginx 服務同域了,也就是說前端這時候對 Nginx 服務發起請求就不會再是跨域。
訪問 Nginx 咱們能夠實現了,接下來要作的就是對請求進行代理轉發。
前端的 Ajax 請求是這樣的:
Nginx 須要對該請求進行攔截,因此能夠作以下配置:
location配置的意思是對包含 「cross_origin」 請求攔截,並對請求路徑進行重寫,一開始請求路徑是 「/cross_origin/get_json?type=20170126」 ,重寫後便成了 「/get_json?type=20170126」,$1表明(.*)中的內容,而(.*)則表明 cross_origin 後面的所有字符,也就是咱們會把 cross_origin 部分去掉,可是保留 cross_origin 以後的全部字符,固然這一步並不是是絕對必要的。接下來咱們再把請求代理到 3000 端口所對應的資源服務,因此請求路徑從一開始的 「127.0.0.1:8080/cross_origin/get_json?type=20170126」 通過代理服務器Nginx以後變成了 「127.0.0.1:3000/get_json?type=20170126」。在 「127.0.0.1:3000」 下存在對應的接口:
如今在前端觸發點擊事件發起請求:
獲得了響應,至此咱們成功發起了跨域請求。
完。