詳細梳理ajax跨域經常使用4種解決方案

前言

自動接觸前端,跨域這個詞就一直縈繞在耳畔。由於通常接手的項目都已經作好了這方面的處理,並且以前一直感受對這方面模棱兩可,因此今天就抽個時間梳理一下。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 下的,明顯構成跨域。

咱們根據項目使用的框架不一樣,處理的方式也不一樣。

一、nodejs+express+http-proxy-middleware 插件代理

若是是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) {},
});
複製代碼

二、webpack-dev-server 代理

咱們常常在vue開發項目的時候,會用webpack做爲前端自動化構建工具的話,也會使用到webpack-dev-server的插件,那麼能夠引用webpack-dev-server來進行配置跨域方案。

webpack-dev-server是一個小型的nodejs服務器,是基於express框架的,用於實時監聽和打包編譯靜態資源。其中裏面有一個屬性是proxy,是專門來配置代理請求接口的。

你只須要在webpack.config.jsdevServer中以下設置便可:

devServer: {
        port: 3000,
        inline: true,
        proxy: {
            "/zhuiszhu": {
                target: "http://39.105.136.190:3000/",
                changeOrigin: true  //必須配置爲true,才能正確代理
            }
        }
    },
複製代碼

其實能夠看出, webpack 的 devServer.proxy 就是使用了很是強大的 http-proxy-middleware 包來實現代理的,因此本質上是相通的。

JSONP

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須要注意:

  1. 必須後端配置相應回調函數。
  2. 只能發送GET請求。

WebSocket

WebSocket是一種通訊協議,使用ws://(非加密)和wss://(加密)做爲協議前綴。該協議不實行同源政策,只要服務器支持,就能夠經過它進行跨源通訊。

因爲發出的WebSocket請求中有有一個字段是Origin,表示該請求的請求源(origin),即發自哪一個域名。

正是由於有了Origin這個字段,因此WebSocket纔沒有實行同源政策。由於服務器能夠根據這個字段,判斷是否許可本次通訊。

CORS

CORS全稱「 Cross-origin resource sharing 」(跨域資源共享),相比JSONP, CORS容許任何類型的請求 。

CORS須要瀏覽器和服務器同時支持。目前,全部瀏覽器都支持該功能,IE瀏覽器不能低於IE10。

整個CORS通訊過程,都是瀏覽器自動完成,不須要用戶參與。對於開發者來講,CORS通訊與同源的AJAX通訊沒有差異,代碼徹底同樣。瀏覽器一旦發現AJAX請求跨源,就會自動添加一些附加的頭信息,有時還會多出一次附加的請求,但用戶不會有感受。

所以,實現CORS通訊的關鍵是服務器。只要服務器實現了CORS接口,就能夠跨源通訊。

總結

綜上,若是訪問的別人服務器的資源,而且未設置JSONP,也未開放WebSocket白名單,也沒有設置CORS接口,那麼惟一的選擇就是使用本身的服務器進行反向代理。

參考連接

瀏覽器同源政策及其規避方法

跨域資源共享 CORS 詳解

express框架介紹

http-proxy-middleware

本文完。

(啾咪 ^.<)

相關文章
相關標籤/搜索