zoukankan      html  css  js  c++  java
  • Vuex、axios以及跨域请求处理

    一、Vuex

    1、介绍

    复制代码
    vuex是一个专门为Vue.js设计的集中式状态管理架构。
    对于状态,我们把它理解为在data中需要共享给其他组件使用的部分数据。
    Vuex和单纯的全局对象有以下不同:
    
        1. Vuex 的状态存储是响应式的。当vue组件从store中读取状态的时候,
        若store中的状态发生变化,那么相应的组件也会相应的得到高效更新。
    
    
        2. 你不能直接改变store中的状态。改变store中的状态的唯一途径就是显示的
        提交(commit)mutation。这样使得我们可以方便的跟踪每一个状态的变化,
        从而让我们能够实现一些工具来帮助我们更好的了解我们的应用。
    复制代码

    2、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/>'
    });
    复制代码

    3、获取数据

    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>
    复制代码

     4、更改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
        }
      }
    })
    复制代码

    二、axios的简单使用

    1、安装

    使用npm安装axios
    -- npm install axios
    
    axios是基于promise用于浏览器和node.js的http客户端

    2、axios基本参数

    复制代码
    url:请求借口地址
    method:请求方式
    data:请求数据
    headers:请求头
    then(function(response){}):请求成功后的回调函数
    catch(function(error){})请求失败后的回调函数
    复制代码

    3、几种请求方法

    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'
      }
    });
    复制代码

    4、示例

    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请求)。
    那怎么处理?继续往下看..
    复制代码

    三、CORS跨域请求介绍

    1、区分简单请求和复杂请求

    复制代码
    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预请求。
    复制代码

    2、请求头

    复制代码
      Accept
        我能解析什么数据类型
      
      ContentType
        我给你的是什么数据类型
      
      数据类型
        application/x-www-from-urlencoded   --> form表单
        multipart/form-data                 --> 文件格式
        text/plain                          --> 文本
        application/json                    --> json格式
        html
        xml
    复制代码

    四、跨域请求处理--jsonp

    1、 原理(现在很少有人使用这种方式处理跨域请求)

    我们可以发现,我们使用CDN引进任何链接的时候,引进了就可以使用了,但是,CDN的链接对于我们来说也是跨域,为什么不会报错呢?
    原因是对于script、link或img这些标签,他们引入CDN只是发送get请求获取资源,浏览器认为这没有风险,所以可以正常进行请求,
    而ajax可以发送任何类型的请求,风险太大,浏览器就自动把它们拦截了(浏览器只阻止表单以及ajax请求)。
    比如script标签src想某个CDN发送get请求,拿到的所有资源就会存在script标签内,你就可以在script标签内使用这些内容。
    但是只能用于发GET请求。

    2、示例

    复制代码
    // 某前端页面代码
    <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")')

    五、CORS跨域请求之简单请求处理

    1、 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

    2、 post跨域简单请求

    注意:前后端分离的项目没办法提交csrf,有些框架是可以默认过滤跳过这个验证,现在的话,我们先在后端把csrf中间件注释掉
    代码跟上面一样,只是在前端把method的提交方式改成post即可

    六、CORS跨域请求之复杂请求处理

    1、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

    2、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

    3、总结

    复制代码
    -- 复杂请求什么不被允许,那么我们就在中间件给它设置成是允许的即可
    -- 前端拿到的响应数据是一个对象,具体的值存在这个对象的data属性里面,取值:响应对象.data
    -- 响应对象还有其他数据:
        config: {...}
        data: "后端返回的具体数据"
        headers: {content-type: "text/html; charset=utf-8"}
        request: XMLHttpRequest {…}
        status: 200
        statusText: "OK"
    复制代码
  • 相关阅读:
    Linux指令面试题01-进程查看与终止
    微信网页授权
    腾讯视频怎么转成mp4模式 软件 工具 方法 最新【已解决】
    表操作,多对一、多对多、一对一
    初识数据库,基础sql语句
    IO多路复用
    协程:gevent
    线程:threading
    进程:multiprocessing
    利用socket与ssl模块读取网页内容
  • 原文地址:https://www.cnblogs.com/yidashi110/p/10091409.html
Copyright © 2011-2022 走看看