Vuex、axios以及跨域請求處理

1、Vuex

一、介紹

複製代碼
vuex是一個專門爲Vue.js設計的集中式狀態管理架構。
對於狀態,咱們把它理解爲在data中須要共享給其餘組件使用的部分數據。
Vuex和單純的全局對象有如下不一樣:

    1. Vuex 的狀態存儲是響應式的。當vue組件從store中讀取狀態的時候,
    若store中的狀態發生變化,那麼相應的組件也會相應的獲得高效更新。


    2. 你不能直接改變store中的狀態。改變store中的狀態的惟一途徑就是顯示的
    提交(commit)mutation。這樣使得咱們能夠方便的跟蹤每個狀態的變化,
    從而讓咱們可以實現一些工具來幫助咱們更好的瞭解咱們的應用。
複製代碼

 

二、vuex的安裝和實例化

1. 安裝命令
--  npm install vuex

 

2. 實例化的兩種方式
複製代碼
方式一:直接在main.js裏面註冊vuex的倉庫實例
// main.js
import Vue from 'vue'
import App from './App'
import Vuex from 'vuex'

// 讓vue實例使用Vuex
Vue.use(Vuex)

Vue.config.productionTip = false

// 實例化Vuex的倉庫,store表明倉庫
const store = new Vuex.Store({
    // state存放全部的公用數據
    state: {
        name : "bdyjy",
    }
});

new Vue({
  el: '#app',
  // 註冊store: store
  store,
  components: { App },
  template: '<App/>'
});
複製代碼
複製代碼
方式二:爲了方便維護,一般在src下面新建一個store文件夾,而後在裏面新建一個index.js
// store/index.js
import Vuex from "vuex"
import Vue from "vue"

Vue.use(Vuex);

// 拋出實例化的Vuex倉庫,store表明倉庫
export default new Vuex.Store({
  // state存放全部的公用數據
  state: {
    name : "bdyjy",
  }
})


// main.js
import Vue from 'vue'
import App from './App'
import store from "./store/index"


Vue.config.productionTip = false

new Vue({
  el: '#app',
  // 註冊store: store
  store,
  components: { App },
  template: '<App/>'
});
複製代碼

 

三、獲取數據

1. state
複製代碼
state是保存咱們data中須要共享的數據。
因爲Vuex的存儲是響應式的,從store實例中讀取狀態可使用:this.$store.state.變量名
且應該在計算屬性中返回某個狀態,由於計算屬性實時在監聽數據,數據變化了,它馬上就能知道,
若是在data屬性中返回某個狀態,那麼這個數據若是在後續變化了,它也不知道了,由於data在加載完成後就不會再監聽這個數據

示例:在某個組件中使用
// course.vue
<template>
    <div>
      <h2>這是課程組件</h2>
      <p>我是{{name}}</p>
    </div>
</template>

<script>
    export default {
      name: "Course",
      // 使用計算屬性獲取倉庫裏面的name變量的值
      computed: {
        name: function () {
          return this.$store.state.name
        }
      }
    }
</script>
複製代碼

 

2. getters
複製代碼
有時候咱們須要從store中的state中派生出一些狀態,例如對數據進行簡單的計算。
而且不少組件都須要用到此方法,咱們要麼複製這個函數,要麼抽取到一個公共函數,多處導入。
咱們vuex提供了更加方便的方法,getters 它就像計算屬性同樣,getters的返回值會根據它的依賴被
緩存起來,只有它的依賴發生改變時,纔會從新計算。

簡單地來講,getters能夠對狀態進行二次處理
複製代碼
複製代碼
1. // store/index.js
import Vuex from "vuex"
import Vue from "vue"

Vue.use(Vuex);

// 拋出實例化的Vuex倉庫,store表明倉庫
export default new Vuex.Store({
  // state存放全部的公用數據
  state: {
    name : "bdyjy",
  },
  // getters對state的值進行二次處理
  getters: {
    friend: function (state) {// 接收state做爲參數
      return state.name + '的朋友是:jty'
    }
  }
})


2. // 在某個組件中使用
// course.vue
<template>
    <div>
      <h2>這是課程組件</h2>
      <p>我是{{name}}</p>
      <p>{{friend}}</p>
    </div>
</template>

<script>
    export default {
      name: "Course",
      computed: {
        name: function () {// 經過state取值
          return this.$store.state.name
        },
        friend: function () {// 經過getters取值
          return this.$store.getters.friend
        }
      }
    }
</script>
複製代碼
複製代碼
1. // store/index.js
import Vuex from "vuex"
import Vue from "vue"

Vue.use(Vuex);

// 拋出實例化的Vuex倉庫,store表明倉庫
export default new Vuex.Store({
  // state存放全部的公用數據
  state: {
    name : "bdyjy",
  },
  // getters對state的值進行二次處理
  getters: {
    friend: function (state) {// 接收state做爲參數
      return state.name + '的朋友是:jty'
    },
    play: function (state, getters) {// 接收state和getters做爲參數
      // 由於要取到friend,就要state
      return getters.friend + '一塊兒玩'
    }
  }
})


2. // 在某個組件中使用
// course.vue
<template>
    <div>
      <h2>這是課程組件</h2>
      <p>我是{{name}}</p>
      <p>{{friend}}</p>
      <p>{{play}}</p>
    </div>
</template>

<script>
    export default {
      name: "Course",
      computed: {
        name: function () {// 經過state取值
          return this.$store.state.name
        },
        friend: function () {// 經過getters取值
          return this.$store.getters.friend
        },
        play: function () {
          return this.$store.getters.play
        }
      }
    }
</script>
複製代碼

 

 四、更改store中的狀態

1. 回想一下非父子之間的組件之間是如何進行通訊的
-- 新建一個新的vue實例當作兩個組件之間通訊的橋樑
-- 一個組件使用 $emit 向這個vue實例提交事件
-- 另外一個組件在加載完成後這個vue實例經過鉤子函數mounted 使用 $on 監聽$emit提交的事件而後處理

 

2. vuex更改store中的狀態相似於上面的步驟
-- 經過this.$store.commit('事件名稱', '數據')提交事件到這個vuex倉庫
-- 在Vuex.Store這個實例裏面經過mutations接收提交過來的事件
-- mutations裏面的事件它會接收state爲第一個參數,後面接收其餘參數

 

3.示例
複製代碼
<template>
  <div>
    <h2>這是學位課程信息</h2>
    <button @click="my_click">點擊展現學位信息</button>
    <h3>{{degree_info}}</h3>
  </div>
</template>

<script>
  export default {
    name: "DegreeCourse",
    computed: {
      degree_info: function () {
        return this.$store.state.degree_info
      }
    },
    methods: {
      // 提交事件到store
      my_click: function () {
        this.$store.commit('degree_info', '博士')
      }
    }
  }
</script>
複製代碼
複製代碼
import Vuex from "vuex"
import Vue from "vue"

Vue.use(Vuex);

// 拋出實例化的Vuex倉庫,store表明倉庫
export default new Vuex.Store({
  state: {
    degree_info: ''
  },
  // commit上來的事件在這裏進行處理
  mutations: {
    degree_info: function (state, data) {
      state.degree_info = data
    }
  }
})
複製代碼

 

2、axios的簡單使用

一、安裝

使用npm安裝axios
-- npm install axios

axios是基於promise用於瀏覽器和node.js的http客戶端

 

二、axios基本參數

複製代碼
url:請求借口地址
method:請求方式
data:請求數據
headers:請求頭
then(function(response){}):請求成功後的回調函數
catch(function(error){})請求失敗後的回調函數
複製代碼

 

三、幾種請求方法

1. get請求
複製代碼
// 攜帶參數的get請求
axios.get('/user?ID=12345')
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });
複製代碼
複製代碼
// 上面的請求能夠這樣作
axios.get('/user', {
    params: {
      ID: 12345
    }
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });
複製代碼

 

2. post請求
複製代碼
axios.post('/user', {
    username: 'xiaoming',
    password: '123abcd'
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });
複製代碼

 

3. 執行多個併發請求
複製代碼
function getUserAccount() {
  return axios.get('/user/12345');
}

function getUserPermissions() {
  return axios.get('/user/12345/permissions');
}

axios.all([getUserAccount(), getUserPermissions()])
  .then().catch();
複製代碼

 

4. axios.request(推薦使用這種)
複製代碼
axios.request({
  method: 'post',  // 請求方式:get、post、delete等等
  url: '/user/12345',
  data: {
    username: 'xiaoming',
    password: '123abcd'
  }
});
複製代碼

 

四、示例

1. 把axios設置成Vue對象屬性
複製代碼
下載好axios後,在須要使用的地方導入axios便可直接使用,axios相似於ajax,用於向後端進行數據傳輸
可是axios是不能註冊到Vue實例裏面,所以不能經過this.$axios進行使用的,由於它不是Vue實例的屬性,
可是咱們就是但願可以經過this.$axios對它進行使用呢,能夠給Vue的原型量prototype增長一個$axios屬性,
而後全部的Vue對象均可以經過this.$axios對它進行使用

// main.js
import axios from "axios"

Vue.prototype.$axios = axios
複製代碼

 

2. Vue代碼
複製代碼
<script>
  export default {
    name: "DegreeCourse",
    mounted(){
      this.$axios.request({
        url: "http://127.0.0.1:8000/test/",  // 後端地址
        method: "get"  // 提交方式
      }).then(function (response) {// then是成功後的回調函數
        console.log(response);
      }).catch(function (error) {// catch是失敗後的回調函數
        console.log(error);
      })
    }
  }
</script>
複製代碼

 

3. 瀏覽器的同源策略
複製代碼
當這個組件加載完後,會自動向後端http://127.0.0.1:8000/test/ 發送 get 請求,
可是這樣發送的請求是屬於跨域請求,因爲瀏覽器的同源策略,服務器給咱們返回的信息瀏覽器會給咱們攔截下來,
因此若是後端返回消息的時候不進行一些處理的話,前端這裏是收不到消息的而且會報錯。(先後端的域名和端口只要其中一個不同,就是跨域),
跨域的ajax請求就會被瀏覽器攔截(axios發送的也是ajax請求)。
那怎麼處理?繼續往下看..
複製代碼

 

3、CORS跨域請求介紹

一、區分簡單請求和複雜請求

複製代碼
HTTP方法是下列方法之一
  HEAD, GET,POST

HTTP頭信息不超出如下幾種字段
  Accept, Accept-Language, Content-Language, Last-Event-ID

  Content-Type只能是下列類型中的一個

    application/x-www-from-urlencoded

    multipart/form-data

    text/plain

任何一個不知足上述要求的請求,即會被認爲是複雜請求
複雜請求會先發出一個預請求,咱們也叫預檢,OPTIONS請求


也就是說,HEAD, GET,POST這三個請求,當它們知足上面的頭信息時,它們就是簡單請求,不然都是複雜請求,
好比一個get請求,可是它請求頭的Content-Type是application/json類型,那麼它也是複雜請求。
複雜請求會先發出一個OPTIONS預請求。
複製代碼

 

二、請求頭

複製代碼
  Accept
    我能解析什麼數據類型
  
  ContentType
    我給你的是什麼數據類型
  
  數據類型
    application/x-www-from-urlencoded   --> form表單
    multipart/form-data                 --> 文件格式
    text/plain                          --> 文本
    application/json                    --> json格式
    html
    xml
複製代碼

 

4、跨域請求處理--jsonp

一、 原理(如今不多有人使用這種方式處理跨域請求)

咱們能夠發現,咱們使用CDN引進任何連接的時候,引進了就可使用了,可是,CDN的連接對於咱們來講也是跨域,爲何不會報錯呢?
緣由是對於script、link或img這些標籤,他們引入CDN只是發送get請求獲取資源,瀏覽器認爲這沒有風險,因此能夠正常進行請求,
而ajax能夠發送任何類型的請求,風險太大,瀏覽器就自動把它們攔截了(瀏覽器只阻止表單以及ajax請求)。
好比script標籤src想某個CDN發送get請求,拿到的全部資源就會存在script標籤內,你就能夠在script標籤內使用這些內容。
可是隻能用於發GET請求。

 

二、示例

複製代碼
// 某前端頁面代碼
<script>
    // 定義一個函數
    function handlerResponse(data) {
        console.log(data)
    }
</script>

// 向後端發送請求,拿到handlerResponse函數並執行
<script src="http://127.0.0.1:8000/test/"></script>
複製代碼
// 某Django後端代碼
class TestView(views.View):
    def get(self, request):
        # 返回一個handlerResponse("ok")字符串
        return HttpResponse('handlerResponse("ok")')

 

5、CORS跨域請求之簡單請求處理

一、 get跨域簡單請求

1. 報錯緣由
Access-Control-Allow-Origin --> 前端這個域不被容許接收後端的數據

 

2. 後端視圖函數
class TestView(views.View):
    def get(self, request):
        return HttpResponse('嘿嘿')

 

3. 後端中間件
複製代碼
from django.utils.deprecation import MiddlewareMixin


class MyCores(MiddlewareMixin):
    def process_response(self, request, response):
        # 給這個響應添加響應頭
        # 告訴瀏覽器我這個後端容許響應頭指定的域拿到個人響應數據(*表明全部域)
        response['Access-Control-Allow-Origin'] = '*'

        # http://localhost:8080表明只能讓這個域拿到個人數據
        # response['Access-Control-Allow-Origin'] = 'http://localhost:8080'
        return response
複製代碼

 

4. 前端Vue
<script>
  export default {
    name: "DegreeCourse",
    mounted(){
      this.$axios.request({
        url: "http://127.0.0.1:8000/test/",  // 後端地址
        method: "get"  // get簡單請求
        // method: "post"  // post簡單請求
      }).then(function (response) {// then是成功後的回調函數
        console.log(response); // 接收到後端response的數據是一個對象
      }).catch(function (error) {// catch是失敗後的回調函數
        console.log(error);
      })
    }
  }
</script>
View Code

 

二、 post跨域簡單請求

注意:先後端分離的項目沒辦法提交csrf,有些框架是能夠默認過濾跳過這個驗證,如今的話,咱們先在後端把csrf中間件註釋掉
代碼跟上面同樣,只是在前端把method的提交方式改爲post便可

 

6、CORS跨域請求之複雜請求處理

一、delete跨域複雜請求

1. 報錯緣由
Access-Control-Allow-Methods --> 這個請求方法不被容許

 

2. 後端視圖函數
class TestView(views.View):
    def delete(self, request):
        return HttpResponse("返回DELETE數據")
View Code

 

3. 後端中間件
class MyCores(MiddlewareMixin):
    def process_response(self, request, response):
        # 給這個響應添加響應頭
        # 告訴瀏覽器我這個後端容許響應頭指定的域拿到個人響應數據(*表明全部域)
        response['Access-Control-Allow-Origin'] = '*'
        # http://localhost:8080表明只能讓這個域拿到個人數據
        # response['Access-Control-Allow-Origin'] = 'http://localhost:8080'

        # 若是是複雜請求,會先發送OPTIONS預檢
        if request.method == 'OPTIONS':
            # 若是是複雜請求的方法不被容許,那麼就給告訴瀏覽器我容許這個複雜請求
            response["Access-Control-Allow-Methods"] = "DELETE"
        return response
View Code

 

4. 前端Vue
<script>
  export default {
    name: "DegreeCourse",
    mounted(){
      this.$axios.request({
        url: "http://127.0.0.1:8000/test/",  // 後端地址
        method: 'delete' // delete複雜請求
      }).then(function (response) {// then是成功後的回調函數
        console.log(response); // 接收到後端response的數據是一個對象
      }).catch(function (error) {// catch是失敗後的回調函數
        console.log(error);
      });
    }
  }
</script>
View Code

 

二、post發送複雜請求

1. 報錯緣由
Access-Control-Allow-Headers --> 這個請求頭的數據類型不被容許

 

2. 後端視圖函數
class TestView(views.View):
    def post(self, request):
        return HttpResponse("返回POST數據")
View Code

 

3. 後端中間件
class MyCores(MiddlewareMixin):
    def process_response(self, request, response):
        # 給這個響應添加響應頭
        # 告訴瀏覽器我這個後端容許響應頭指定的域拿到個人響應數據(*表明全部域)
        response['Access-Control-Allow-Origin'] = '*'
        # http://localhost:8080表明只能讓這個域拿到個人數據
        # response['Access-Control-Allow-Origin'] = 'http://localhost:8080'

        # 若是是複雜請求,會先發送OPTIONS預檢
        if request.method == 'OPTIONS':
            # 若是是複雜請求的方法不被容許,那麼就給告訴瀏覽器我容許這個複雜請求
            response["Access-Control-Allow-Methods"] = "DELETE"
            # 告訴瀏覽器這個請求頭的數據類型我是容許的
            response["Access-Control-Allow-Headers"] = "Content-Type"
        return response
View Code

 

4. 前端Vue
<script>
  export default {
    name: "DegreeCourse",
    mounted(){
      this.$axios.request({
        url: "http://127.0.0.1:8000/test/",  // 後端地址
        method: 'post', // post發送複雜請求
        contentType: "application/json",
        data: {
          "author": "狗屎"
        }
      }).then(function (response) {// then是成功後的回調函數
        console.log(response); // 接收到後端response的數據是一個對象
      }).catch(function (error) {// catch是失敗後的回調函數
        console.log(error);
      })

    }
  }
</script>
View Code

 

三、總結

複製代碼
-- 複雜請求什麼不被容許,那麼咱們就在中間件給它設置成是容許的便可
-- 前端拿到的響應數據是一個對象,具體的值存在這個對象的data屬性裏面,取值:響應對象.data
-- 響應對象還有其餘數據:
    config: {...}
    data: "後端返回的具體數據"
    headers: {content-type: "text/html; charset=utf-8"}
    request: XMLHttpRequest {…}
    status: 200
    statusText: "OK"
複製代碼
相關文章
相關標籤/搜索