前端如何解決跨域

第一篇掘金博客,我想研究一下跨域這個問題。校招面試常被問到的問題,什麼是跨域?如何解決跨域問題?這是兩個高頻被問的兩個問題,雖然理論上能將這個問題回答過去,可是真正在項目中遇到跨域問題就犯難了。今天這篇文章適合跟我同樣的小白閱讀。css

學完這篇文章,咱們能夠回答出如下幾個問題html

  • 什麼是跨域?前端

  • 跨域問題的產生以及意義vue

  • CORS跨域資源共享node

  • 解決跨域請求jquery

  • 如何使用proxyTable 解決開發環境的跨域webpack

    之前咱們先後端不分離時代,咱們前端只須要寫最基礎的html、css,而後將文件發給後臺開發人員。咱們都是用服務器來渲染的,這樣前端與服務器的代碼徹底在一塊兒,在同一個web服務器裏面,同一個服務不存在跨域這個問題。web

    後來隨着前端飛速發展,想要實現異步、無刷新操做,咱們開始使用ajax實現異步無刷新操做,效果驚人,這時候部署還會將前端代碼與服務器代碼放在同一個web服務器上,這也不會形成跨域問題。這就屬於同源策略,域名、協議、端口相同。想要同源,這就要求前端開發人員也得須要使用後端的編譯器,好比eclipse,本身跑項目才能順利開發前端代碼。面試

什麼是跨域

跨域實際上也叫作非同源策略請求。 談到跨域問題,咱們必須先了解一下什麼是同源策略?ajax

同源策略:它是由Netscape提出的一個著名的安全策略。如今全部支持JavaScript 的瀏覽器都會使用這個策略。所謂同源是指,域名,協議,端口相同。
域名,協議,端口,三者所有相同就是同源,其中一個不一樣就是**跨域**

web服務器:  http://127.0.0.1:3000/index.html
接口地址:    http://127.0.0.1:4000/list

在這個項目中,域名相同,協議相同,端口號不同,跨域
複製代碼

跨域解決方案:

一、JSONP實現跨域

原理:jsonp實現跨域的原理是跨域的服務端把客戶端所須要的數據放進客戶端本地的一個js方法裏,進行調用,客戶端在本地的js對返回的數據進行處理。這樣就實現了不一樣域名下的兩個站點間的交流。

基於script無跨域限制幫我咱們帶到服務器上,而後利用callback回調函數作一些咱們想作的事, callback=fun function fun(){//基於script無跨域限制幫咱們帶到服務器上,而後把本地的函數傳遞給服務器,服務器就能夠接到請求,同時也能拿到callback傳過來的func、服務器一、準備數據json格式的 data={...} 二、給客戶端返回數據func(+JSON.stringify(data)+) ,三、客戶端拿到數據 注:一、func得是全局函數。二、JSONP須要服務器端的支持服務器端

script、img、link、iframe這些標籤能夠跨域

例以下面的代碼,既能夠訪問本身的,也能夠訪問跨域的。
複製代碼
客戶端請求:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
    <title>Document</title>
</head>
<body>
</body>
<script>
//jquery支持jsonp請求
    $.ajax({
        //發送ajax
        url: 'http://127.0.0.1:8001/list',//請求地址
        method: 'get',   //請求方式只能是get方式,這也是jsonp跨域的一個缺點
        dataType: 'jsonp',  //=>執行的是JSONP請求
        success: res => {
            console.log(res)
        }
    })  //客戶端
    console.log('aaa')
</script>

</html>
複製代碼
服務端用node來實現:
let express = require('express'),
    app = express();
app.listen(8001, _ => {
    console.log('OK!')
})
app.get('/list', (req, res) => {
    let { callback = Function.prototype } = req.query  //解構出來,設置默認值Function.prototype匿名空函數,
    //callback與ajax的回調函數綁定
    let data = {
        code: 0,
        meg: '這就是我要返回的數據'
    }   //返回給服務器的數據
    res.send(`${callback}(${JSON.stringify(data)})`)//拿到的數據返回(注:數據服務器能夠插入任何惡意代碼)
})
複製代碼

http://127.0.0.1:8001/list?callback=jQuery214085466902496328_1593939725240&_=1593939725241 

上面發了list請求,傳了一個callback函數,這個函數是jquery幫咱們建立出來的隨機的的全局函數。

response返回的結果以下圖:jquery建立的隨機全局函數包着咱們的數據,當咱們瀏覽器拿到這個結果之後,就會把全局函數執行。全局函數會幫咱們默認執行success執行,把數據傳給res。
複製代碼

jquery在這個過程當中幫咱們完成了取值的過程:

  • jquery幫咱們默認建立一個全局函數
  • 幫咱們默認建立script向咱們服務器發請求,
  • 幫咱們默認執行全局函數的時候,把success執行,拿到咱們的數據。

二、CORS實現跨域

CROS(Cross-Origin Resource Sharing)跨源資源分享。

CROS容許瀏覽器向跨源服務器發出XMLHttpRequest請求,克服了ajax不能跨源請求的限制🚫。 CROS通訊的主要在於服務器,只要服務器實現CROS接口,就能夠實現跨域請求。

瀏覽器在頭信息中增長一個Origin字段,從而發出CROS請求
   要支持CORS訪問須要服務器在響應頭中添加Access-Control-Allow-Origin,可使用*來表示容許全部域跨域訪問。
複製代碼

詳細的介紹能夠參考阮一峯老師的這篇文章:www.ruanyifeng.com/blog/2016/0…

三、 vue項目開發使用proxyTable 解決開發環境的跨域

這是我想重點介紹的,由於公司前端頁面是基於vue實現的,前端使用vue-cli腳手架搭建的vue項目作開發的時候,項目自己啓動本地服務須要佔用一個端口。咱們在與後端服務器接口聯調的時候,必定會產生跨域問題。大多數公司都是採用先後端分離的開發模式,必然會產生跨域。咱們儘可能在前端去解決跨域問題,避免更改後端代碼。

如今不少項目使用webpack自動化構建前端項目,在webpack項目中咱們使用ProxyTable來實現跨域。 ProxyTable實現跨域原理:

ProxyTable底層採用了http-proxy-middleware,這是http代理中間件。
    咱們在項目根目錄的config文件夾下找到的index.js文件
複製代碼

(1)利用vue-cli腳手架搭建一個vue項目

下面的步驟是基於你已經安裝了nodejs、npm,(能夠安裝一個全局的淘寶鏡像cnpm速度會比較快) npm install cnpm -g --registry=https://registry.npm.taobao.org

步驟:

  • cnpm install -g vue-cli //全局安裝vue-cli

  • cd進入你想放置項目的文件夾

  • 在當前文件夾下執行 vue init webpack

  • cnpm i //安裝依賴包

  • npm run dev // 執行項目

  • 至此咱們已經利用vue-cli搭建好了vue項目

(2)配置跨域

打開剛剛搭建好的vue項目的config文件夾下的index.js文件,在proxyTable對象中填寫須要被代理的api,

proxyTable: {
      //配置特定的請求代理到對應的API接口
      //請求接口爲/HomeApi被代理到  http://10.64.61.129:3000/home
      "/HomeApi": {
        target: "http://10.64.61.129:3000/home",  //目標地址
        changeOrigin: true,  //是否開啓代理
        pathRewrite: {
          '^/HomeApi': ''
        }
      },
      //請求的藉口 /details被代理到  http://10.64.61.129:3000/details
      "/DetailsApi": {
        target: "http://10.64.61.129:3000/details",  // 目標地址
        changeOrigin: true,
        pathRewrite: {
          '^/HomeApi': ''
        }
      },
    },
複製代碼

注:藉口本來爲/payment/list,爲了匹配代理地址,咱們在前面加上/HomeApi,就能夠被分發到/HomeApi中,所以咱們須要將接口地址寫成/HomeApi/payment/list。被分配到指定的代理中,咱們經過寫 pathRewrite:{'^/HomeApi': ''}重寫路徑,去掉咱們以前爲了匹配代理而加上的/HomeApi。

參考: www.cnblogs.com/gpd-Amos/p/…

參考: www.cnblogs.com/liyuspace/p…

相關文章
相關標籤/搜索