自動接觸前端,跨域這個詞就一直縈繞在耳畔。由於通常接手的項目都已經作好了這方面的處理,並且以前一直感受對這方面模棱兩可,因此今天就抽個時間梳理一下。javascript
跨域這個概念來自一個叫 「同源策略」 的東西。同源策略是瀏覽器(注意是瀏覽器,跟通訊協議無關)上爲了安全考慮實施的很是重要的安全機制。html
Ajax
默認只能獲取到同源的數據,對於非同源的數據,Ajax是獲取不到的。前端
- 協議相同
- 域名相同
- 端口相同
舉例來講,http://www.example.com/dir/page.html
這個網址,協議是http://
,域名是www.example.com
,端口是80
(默認端口能夠省略)。這個網址,在這個地址中要去訪問下面服務器的數據,那麼會發生什麼狀況呢?vue
URL | 結果 | 緣由 |
---|---|---|
https://www.example.com/dir/other.html |
不一樣源 | 協議不一樣,https 和 http |
http://en.example.com/dir/other.html |
不一樣源 | 域名不一樣 |
http://www.example.com:81/dir/other.html |
不一樣源 | 端口不一樣 |
http://www.example.com/dir/page2.html |
同源 | 協議,域名,端口都相同 |
http://www.example.com/dir2/page.html |
同源 | 協議,域名,端口都相同 |
那麼。想要獲取非同源地址的數據,就要使用跨域。不管是 Ajax 仍是跨域,都是爲了訪問服務器的數據。簡單的來講, Ajax 是爲了訪問本身服務器的數據,跨域是爲了訪問別人服務器的數據(好比獲取天氣信息,航班信息等)。java
爲了保證用戶信息的安全,防止惡意的網站竊取數據。node
「 設想這樣一種狀況:A網站是一家銀行,用戶登陸之後,又去瀏覽其餘網站。若是其餘網站能夠讀取A網站的 Cookie,會發生什麼?webpack
很顯然,若是 Cookie 包含隱私(好比存款總額),這些信息就會泄漏。更可怕的是,Cookie 每每用來保存用戶的登陸狀態,若是用戶沒有退出登陸,其餘網站就能夠冒充用戶,隨心所欲。由於瀏覽器同時還規定,提交表單不受同源政策的限制。git
因而可知,"同源政策"是必需的,不然 Cookie 能夠共享,互聯網就毫無安全可言了。」github
via@ 阮一峯web
- 反向代理
- JSONP
- WebSocket
- CORS(根本解決方案)
反向代理就是使用本身的服務器,在後端請求目標服務器的數據,而後返回給客戶端。至關於作了一把中間人的感受。
反向代理服務器,最經常使用的就是Nginx
。可是做爲前端代碼實現的Node.js
也能夠搭建反向代理服務器。
下面來簡要介紹使用node服務進行反向代理。
要實現這個前提是,前端開發環境必須運行在nodejs服務中,所幸的是,如今前端的開發自動化工具都是創建在nodejs上的,因此這個前提也不是很重要。
好比我有一個後端接口:http://39.105.136.190:3000/zhuiszhu/goods/getList
,能夠獲取一些商品列表數據,可是我運行的node項目是在 localhost:3000
下的,明顯構成跨域。
咱們根據項目使用的框架不一樣,處理的方式也不一樣。
若是是express項目,可使用http-proxy-middleware
來處理,這個插件主要用於將前端請求代理到其它服務器。
用法很簡單。你能夠參考插件github官網: github.com/chimurai/ht…
首先須要在你的express項目中安裝該插件:
npm install --save-dev http-proxy-middleware
複製代碼
而後在 app.js
中進行代理設置(示例以下):
var express = require('express');
var proxy = require('http-proxy-middleware');
var app = express();
app.use('/zhuiszhu', proxy({target: 'http://39.105.136.190:3000/', changeOrigin: true}));
app.listen(3000);
複製代碼
以後再項目中再次發送ajax請求的時候,能夠看到數據能夠收到了。
$.ajax({
url: '/zhuiszhu/goods/getList',
type: 'GET',
success(res) {},
});
複製代碼
咱們常常在vue開發項目的時候,會用webpack做爲前端自動化構建工具的話,也會使用到webpack-dev-server
的插件,那麼能夠引用webpack-dev-server
來進行配置跨域方案。
webpack-dev-server是一個小型的nodejs服務器,是基於express框架的,用於實時監聽和打包編譯靜態資源。其中裏面有一個屬性是proxy,是專門來配置代理請求接口的。
你只須要在webpack.config.js
中 devServer
中以下設置便可:
devServer: {
port: 3000,
inline: true,
proxy: {
"/zhuiszhu": {
target: "http://39.105.136.190:3000/",
changeOrigin: true //必須配置爲true,才能正確代理
}
}
},
複製代碼
其實能夠看出, webpack 的 devServer.proxy 就是使用了很是強大的 http-proxy-middleware 包來實現代理的,因此本質上是相通的。
JSONP基本思想是,網頁經過添加一個<script>
元素,向服務器請求JSON數據,這種作法不受同源政策限制;服務器收到請求後,將數據做爲參數放在一個指定名字的回調函數裏傳回來,這個回調函數的名字咱們須要經過js定義好。
好比:當頁面資源加載完畢時候,獲取跨域的數據,而且制定回調函數的名字爲foo
:
window.onload = function () {
var script = document.createElement("script");
script.setAttribute("type","text/javascript");
script.src = "http://bbb.com?callback=foo;
document.body.appendChild(script);
};
foo(data) {
console.log(data); // data即爲跨域獲取到的數據
}
複製代碼
在服務器那邊,須要將數據放入foo函數的參數中:
foo('hello world')
複製代碼
使用JSONP須要注意:
- 必須後端配置相應回調函數。
- 只能發送
GET
請求。
WebSocket是一種通訊協議,使用ws://
(非加密)和wss://
(加密)做爲協議前綴。該協議不實行同源政策,只要服務器支持,就能夠經過它進行跨源通訊。
因爲發出的WebSocket請求中有有一個字段是Origin
,表示該請求的請求源(origin),即發自哪一個域名。
正是由於有了Origin
這個字段,因此WebSocket纔沒有實行同源政策。由於服務器能夠根據這個字段,判斷是否許可本次通訊。
CORS全稱「 Cross-origin resource sharing 」(跨域資源共享),相比JSONP, CORS容許任何類型的請求 。
CORS須要瀏覽器和服務器同時支持。目前,全部瀏覽器都支持該功能,IE瀏覽器不能低於IE10。
整個CORS通訊過程,都是瀏覽器自動完成,不須要用戶參與。對於開發者來講,CORS通訊與同源的AJAX通訊沒有差異,代碼徹底同樣。瀏覽器一旦發現AJAX請求跨源,就會自動添加一些附加的頭信息,有時還會多出一次附加的請求,但用戶不會有感受。
所以,實現CORS通訊的關鍵是服務器。只要服務器實現了CORS接口,就能夠跨源通訊。
綜上,若是訪問的別人服務器的資源,而且未設置JSONP,也未開放WebSocket白名單,也沒有設置CORS接口,那麼惟一的選擇就是使用本身的服務器進行反向代理。
本文完。
(啾咪 ^.<)