天天看点

Vue学习手册(五)-----网络请求axios一、后台介绍二、分项讲解二、封装axios

目录

  • 一、后台介绍
    • 1.1 基础介绍
    • 1.2 fastmock简介
    • 1.3 请求及响应
      • 1.3.1 请求体格式
      • 1.3.2 响应体格式
  • 二、分项讲解
    • 1.1 单一请求
    • 1.2 并发请求
    • 1.3 通用配置
    • 1.4 拦截器
      • 1.4.1 请求拦截
      • 1.4.2 响应拦截
  • 二、封装axios
    • 2.1 vue代理
      • 2.1.1 跨域简介
      • 2.1.2 vue跨域
    • 2.2 封装代码
      • 2.2.1 封装axios实例---request.js
      • 2.2.2 封装请求---http.js
      • 2.2.3 封装业务---api_studetail.js
    • 2.2.4 组件调用/views/about.vue

一、后台介绍

1.1 基础介绍

  • 前后端分离:后端只提供接口及接口文档,前端向接口提交请求即可,遵循restful接口规范
  • 种类:
    • 自有后端:用DRF写接口API,跑在本地使用,具体点击此处跳转
    • 在线接口:mock可以让你在没有后端程序的情况下能真实地在线模拟ajax请求,此为fastmock网站入口

1.2 fastmock简介

  • 新建项目接口页面
    Vue学习手册(五)-----网络请求axios一、后台介绍二、分项讲解二、封装axios
  • 编辑页面
    Vue学习手册(五)-----网络请求axios一、后台介绍二、分项讲解二、封装axios
  • 查看页面
    • 请求写法
      Vue学习手册(五)-----网络请求axios一、后台介绍二、分项讲解二、封装axios
    • 响应内容
      Vue学习手册(五)-----网络请求axios一、后台介绍二、分项讲解二、封装axios
注意:get方法好写,其他方法需要学学mock语法,见接口主页面的使用文档

1.3 请求及响应

1.3.1 请求体格式

  • 功能:向后端发送的请求,包含附加信息(需与后端约定)
  • 出处:在request.js中初始化对象config,增加或覆盖congfig属性项详见http.js
  • config格式如下:
    Vue学习手册(五)-----网络请求axios一、后台介绍二、分项讲解二、封装axios
上述格式:可在request.js的config中

console.log(config)

打印

1.3.2 响应体格式

Vue学习手册(五)-----网络请求axios一、后台介绍二、分项讲解二、封装axios
  • config:请求体配置信息,同1.3.1
  • data:响应体,即服务器响应的数据
  • headers:服务器响应头,服务器对响应进行说明和信息提醒
  • status:响应http状态码,200为响应成功
  • statusText:来自服务器的响应状态信息,‘OK’为响应成功
  • request:浏览器提供的XMLHttpRequest对象,该对象来发送Ajax请求(了解即可)
上述格式:可在about组件调用处res => {console.log(res)}打印

二、分项讲解

1.1 单一请求

  • 安装:

    npm install axios -S

    ,要有node环境
  • 使用:以下写在组件的script标签里
    // 不加相对路径,程序会到node_modules文件夹中去找
    import axios from 'axios'							
    
    // 	axios是使用promise语法
    axios({			
    	// 接口网址:包含协议名,域名,端口和路由							
    	url: 'http://192.168.1.123:3000/home/data',		
    	// 请求方式,默认为get,可以不写
    	method: 'get',				
    	// 请求可以携带的参数,用对象来写,get方法对应params,其他方法对应data
    	params: {										
    		name: 'book',
    		page: 1
    	}
    // 成功请求回数据后,进入then,并用console.log打印结果
    }).then(res => {									
    	console.log(res);
    })
               
    axios写法:
    • 通用写法:axios(),需包含method(默认为get),URL,params或data项
    • 增:axios.post(),需包含URL,data项
    • 删:axios.delete(),需包含URL,data项(可选)
    • 改:axios.put(),需包含URL,data项
    • 局部改axios.patch(),需包含URL,data项
    • 查:axios.get(),,需包含URL,params项(可选)

1.2 并发请求

  • 使用场景:需要等待多个请求都返回后(例如:验证账户+请求数据)才进行后续的操作
  • 以下写在组件的script标签里
  • 核心写法:

    axios.all([axios.get(),axios.get()]).then()

    ,也可用async语法替换,见封装
    import axios from 'axios'							
    
    export defaule {									
    	name : 'app',		
    	// 组件创建时即请求数据						
    	created() {										
    		axios.all([axios.get('http://192.168.99.123:8000/category'),
    				   axios.get('http://192.168.99.123:8000/product')])
    		// axios提供spread方法将两次请求的响应体分别放在res1和res2中
    		.then(axios.spread((res1, res2) => {		
    			// 浏览器终端打印响应体
    			console.log(res1);						
    			console.log(res2);
    		}))
    	}
    }
               

1.3 通用配置

  • 代码(了解)
    // 此时再写axios.get('/category') 就可以访问了
    axios.defaults.baseURL = 'http://192.168.99.123:8000'  
    // 超时设置,为5000毫秒
    axios.defaults.timeout = 5000			
    // 跨域是否带Token			   
    axios.defaults.withCredentials = false			
    // 身份验证信息	   
    axios.defaults.auth = { uname: 'doubi', pwd: '123'}	   
               

1.4 拦截器

1.4.1 请求拦截

  • 功能:
    • 请求体数据过滤操作:如json化请求体参数
    • 显示给用户的动画:请求过程中
    • 请求头检查或修改:例如:token
  • 写法:
    instance.interceptors.request.use(config => {
    	// 用户操作语句
    	console.log(config);		
    	// 此语句必须要有,否则,发出的请求就在这里被拦截掉了			
    	return config		
    	// 有错误可以在此处做细化显示处理				
    	}, err => {
    	console.log(err);
    	}
    )
               

1.4.2 响应拦截

  • 功能:
    • 预处理:对服务器返回的响应数据进行预处理
    • 动画:关闭响应动画,进入页面
  • 写法:
    instance.interceptors.response.use(res=> {
    	// 用户操作语句
    	console.log(res);				
    	// 此语句必须要有,否则,服务器响应就在这里被拦截掉了	
    	return res
    	// 有错误可以在此处做细化显示处理							  		 
    	}, err => {
    	console.log(err);
    	}
    )
               

二、封装axios

2.1 vue代理

2.1.1 跨域简介

  • 跨域攻击:
    • 名称:跨站请求伪造,全称Cross-site request forgery,缩写为CSRF/XSRF
    • 效果:攻击者盗用了你的身份,以你的名义发送恶意请求
    • 示例:当点击图片,会触发页面1的转账动作,银行接收请求,转账
      Vue学习手册(五)-----网络请求axios一、后台介绍二、分项讲解二、封装axios
  • 跨域界定:协议(http),域名(baidu.com),端口(80),有一个不同即为跨域,不包括路由

2.1.2 vue跨域

  • vue服务器:vue脚手架中安装了一个服务器(@vue/cli-service ),

    npm run serve

    命令就是启动这个服务器,显示的网址指向vue服务器
  • vue跨域:vue项目通过axios向后端发起请求的域名与vue服务器的域名不同触发跨域(跨域界定)
  • vue代理服务器工作流程:
    1. vue脚手架启动一个代理服务器(配置vue.config.js)
    2. axios的所有请求会被转发到vue代理服务器并提取请求头中的路由做匹配

      a. 若路由符合匹配规则

      ----代理服务器替用户向后端发请求

      ----代理服务器将后端响应(响应头、响应体)处理后返给浏览器

      b. 若路由不符合匹配规则

      ----请求被发送到vue服务器

      ----响应被直接返回给浏览器

    注意:此服务器仅在开发环境使用,生产环境跨域可用nginx反向代理解决
  • 代理服务器
  • 位置:新建vue.config.js,目录中跟/src为同级,注意修改完这个文件要重启vue项目
  • 文件代码
    // 此也为vue/cli3的配置目录,有则自动加载,没有则使用脚手架默认,
    module.exports = {
    	// 代理服务器专项设置
        devServer: {
        	// 设置被代理的域名
            host: "localhost",
            // 设置被代理的端口
            port: 8080,
            // 被代理是否为https协议
            https: false, 
            // 是否为热更新
            hotOnly: true, 
            // 适合多个后端:转发相关配置
            proxy: { 
            	// 此为全字符匹配:当$version(见api文件夹下的文件)为这个字符串
                "/api/1.0": {
                	// 被代理的域名和端口会被转发到以下目标处,此网址表示后端在本地
                    target: "http://127.0.0.1:8000",
                    // 开启websocket支持
                    ws: true, 
                    // 是否为https
                    secure: false,
                    // 开启pathrewrite功能
                    changeOrigin: true,
                    // 路由改写:将开头的路由’/api/1.0‘换成‘空’(路由见api文件夹下的文件)
                    // 建议路由匹配、此处路由改写和$version(api文件内)三者统一取相同
                    pathRewrite: {
                        '^/api/1.0': ''
                    }
                },
            	// 此为全字符匹配:当$version(见api文件夹下的文件)为这个字符串
                "/api/2.0": {
                	// 被代理的域名和端口会被转发到以下目标处,此网址表示后端在线上(fastmock)
                    target: "https://www.fastmock.site/mock/9eec7517a4e6",
                    // 开启websocket支持
                    ws: true, 
                    // 是否为https
                    secure: false,
                    // 开启pathrewrite功能
                    changeOrigin: true,
                    // 路由改写:将开头的路由‘/api/2.0’换成‘/api/books’
                    // 建议路由匹配、此处路由改写和$version(api文件内)三者统一取相同
                    pathRewrite: {
                        '^/api/2.0': '/api/books'
                    }
                }	// 注意复合下大括号,经常会不成对
            }
        }
    }
               

2.2 封装代码

  • 文件组织
    Vue学习手册(五)-----网络请求axios一、后台介绍二、分项讲解二、封装axios
  • 各文件说明
    • request.js:最基础,最重要,封装axios实例,包含公共的请求配置信息、请求及响应拦截
    • http.js:在上一文件基础上,封装get\post\put\delete请求,返回request.js封装的axios实例
    • api文件夹:在上一文件基础上,封装业务请求,文件夹内按业务逻辑再分文件

2.2.1 封装axios实例—request.js

  • 代码写法
    import axios from 'axios'
    
    // 1.创建axios实例
    const service = axios.create({
            // 请求域名:此处会在运行时自动替换为http://localhost:8080
            baseURL: process.env.BASE_API,
            // 超时时间:单位是ms,请求超过此时间仍无反应报错
            timeout: 3 * 1000
        })
        
    // 2.请求拦截器:发请求前做的一些处理,如配置请求头,设置token,设置loading等,按需添加
    service.interceptors.request.use(config => {
        //数据转化:前后端的所有方法,我统一用data传参
        // 将请求体data格式化为json,如果这一项有值
        config.data = JSON.stringify(config.data); 
        // Content-Type标头:告诉后端发送过去的请求体(即上述两个)的内容类型,常用如下:
        // 	application/octet-stream : 二进制流数据(如常见的文件下载)
        // 	application/x-www-form-urlencoded:form表单数据为key/value格式
        config.headers = {	
        		// 请求体为json格式
                'Content-Type': 'application/json' 
            }
        // 返回请求配置信息
        return config
    }, error => {
    	// 请求拒绝处理
        Promise.reject(error)
    })
    
    // 3.响应拦截器:接收到后端响应后的一些共有处理
    service.interceptors.response.use(response => {
        // 响应体无关部分都过滤掉,只将data返回给组件使用
        return response.data;   
    // 异常处理
    }, error => {
        return Promise.resolve(error.response)
    })
    
    //4.导出给http.js使用
    export default service
               

2.2.2 封装请求—http.js

  • 功能:此处封装的重点是方法,将各个方法通用部分集合在此处写
  • 代码
    import request from './request'
    
    const http = {
    	// 查操作
        get(url, params) {
        	// 初始化request.js中的config对象,请求拦截器就是拦截它的
            const config = {
                method: 'get',
                url: url
            }
            // if语句:如果传了params就设置,没传就不设置
            if (params) config.data = params
            // 返回组合好的axios实例传给上层API业务封装使用
            return request(config)
        },
        // 增操作
        post(url, params) {
            const config = {
                method: 'post',
                url: url
            }
            // congfig请求体:用data传参
            if (params) config.data = params
            return request(config)
        },
        // 改操作(每个参数都必须传)
        put(url, params) {
            const config = {
                method: 'put',
                url: url
            }
            if (params) config.data = params
            return request(config)
        },
        // 改操作(至少传一个参数即可)
        patch(url, params) {
            const config = {
                method: 'patch',
                url: url
            }
            if (params) config.data = params
            return request(config)
        },
        // 删操作
        delete(url, params) {
            const config = {
                method: 'delete',
                url: url
            }
            if (params) config.data = params
            return request(config)
        }
    }
    // 导出给上层API业务封装使用
    export default http
               

2.2.3 封装业务—api_studetail.js

  • 功能:此处封装的重点根据业务逻辑组合路由与方法,需熟悉restful路由规则
  • 位置:/src/utils/api/api_studetail.js
  • 代码
    import http from '@/utils/http'
    
    // 此处version变量(自定义的)影响到vue代理服务器路由匹配
    let version = "/api/1.0"
    // 用于改、局部改、删操作,明确指定操作对象,let为ES6语法
    let id = null
    // 导出全部给vue组件调用
    export default {
        // restful路由:获得stu表中全部数据,注意:结尾最好加斜杠“/”
        getStudetailListAPI(params) {
        	// 注意这里不是单引号,tab键上面那个键的点,${}为js取变量值方法
        	// return返回的是个promise,以下return的都是
            return http.get(`${version}/studetail/`, params)
        },
        // restful路由:在studetail表末尾新增一条记录
        postStudetailAPI(params) {
            return http.post(`${version}/studetail/`, params)
        },
        // restful路由:修改studetail表指定记录
        putStudetailAPI(params) {
            // 后端遇到非get方法会自动忽略id,但路由需要id来明确用户要操作的记录
            id = params.id
            return http.put(`${version}/studetail/${id}/`, params)
        },
        // restful路由:修改stu表指定记录,promise语法.then会返回这条记录
        patchStudetailAPI(params) {
            // 后端遇到非get方法会自动忽略id,但路由需要id来明确用户要操作的记录
            id = params.id
            return http.patch(`${version}/studetail/${id}/`, params)
        },
    
        deleteStudetailAPI(params) {
            // 后端遇到非get方法会自动忽略id,但路由需要id来明确用户要操作的记录
            id = params
            return http.delete(`${version}/studetail/${id}/`)
        }
    }
               

2.2.4 组件调用/views/about.vue

  • 效果图
    Vue学习手册(五)-----网络请求axios一、后台介绍二、分项讲解二、封装axios
  • 代码
    • html部分
      <template>
        <div class="about">
          <h1>学生表</h1>
          <table>
            <thead>
              <tr>
                <th>学生序号</th>
                <th>生日</th>
                <th>身高</th>
                <th>性别</th>
              </tr>
            </thead>
            <tbody v-for="item in studetails" :key="item.id">
              <tr>
                <td>{{item.id}}</td>
                <td>{{item.birthday}}</td>
                <td>{{item.height}}</td>
                <td>{{item.gender}}</td>
              </tr>
            </tbody>
          </table>
          <div>
            <h1>测试按钮</h1>
            <button @click="post_test">测试post</button>
            <button @click="put_test">测试put</button>
            <button @click="patch_test">测试patch</button>
            <button @click="delete_test">测试delete</button>
          </div>
        </div>
      </template>
                 
    • js部分(重点)
      <script>
      	// 调用接口文件
      	import studetail from '@/utils/api/api_studetail'
      	
      	export default {
      	  name:'about',
      	  data(){
      	    return {
      	      // 存储get返回数据,给v-for循环使用
      	      studetails: [],
      	      // 存储id,给非get方法传参paramas,进而在api_studetail文件中修改路由
      	      id:null,
      	      // 给post方法提供数据,此处写死了,以后可以前端构造生成
      	      studetail_post: {birthday: "1979-11-17",height: 175.3,gender: 0},
      	      // 给put方法提供数据,此处写死了,以后可以前端构造生成
      	      studetail_put: {birthday: "1987-1-22",height: 180.3,gender: 1},
      	      // 给patch方法提供数据,此处写死了,以后可以前端构造生成
      	      studetail_patch: {height: 179.3}
      	    }
      	  },
      	  methods:{
      	  	// 功能:向后端请求数据,然后赋值给studetails变量进行前端渲染
      	  	// 注意:res经过响应拦截器处理,标准promise写法
      	    axiosload(){
      	      studetail.getStudetailListAPI()
      	      .then(res=>{this.studetails = res})
      	      .catch(err=>{console.log(err)})
      	    },
      		
      		// 功能:向studetail表中新增一条记录,数据为studetail_post
      		// async函数:为promise语法糖,除await关键字,意义同promise意义
      	    async post_test(){
      	      try {
      	      	// 后端会将成功添加的数据返回前端,此处res接收到新增的记录
      	        let res = await studetail.postStudetailAPI(this.studetail_post);
      	        // 新增完记录,重新请求数据,页面动态更新获得的数据
      	        this.axiosload()
      	        // 提取记录的id给组件中的this.id,给后续put/patch/delete方法使用
      	        this.id = res.id
      	      // 异常处理,同promise中的.catch语句
      	      }catch(err){console.log(err)}},
      	
      		// 功能:修改studetail表中的记录,数据为this.id当前指向的记录
      	    put_test(){
      	      // js对象新增项并赋值的方法,此处接收this.id的值
      	      this.studetail_put['id'] = this.id
      	      studetail.putStudetailAPI(this.studetail_put)
      	      .then(res => {this.axiosload();this.id = res.id;})
      	      .catch(err=>{console.log(err)})
      	    },
      	
      		// 同put方法
      	    patch_test(){
      	      this.studetail_patch['id'] = this.id
      	      studetail.patchStudetailAPI(this.studetail_patch)
      	      .then(res => {this.axiosload();this.id = res.id;})
      	      .catch(err=>{console.log(err)})
      	    },
      		
      		// 功能:删除this.id当前指向的记录
      	    delete_test(){
      	      studetail.deleteStudetailAPI(this.id)
      	      .then(res => {this.axiosload();})
      	      .catch(err=>{console.log(err)})
      	    }
      	  },
      
      	  // 此处意义为,当组件创建还未挂载时,就调用方法请求数据
      	  created(){
      	    this.axiosload()
      	  }
      	}
      </script>
                 
      • 异步:前置程序的执行不影响后续程序语句的执行,即后续程序语句有可能先于前置程序语句执行完毕
      • 同步:与异步相反,即程序按照书写顺序严格的一行一行执行
      • 举个例子:假如你打电话去书店订书, 老板说我查查, 你不挂电话在等待, 老板把查到的结果告诉你, 这是同步;如果老板说我查查, 回头告诉你, 你把电话挂了, 这是异步
      axios:axios为基于promise的http库,属于异步语句,故promise语句后的语句有可能在其执行完毕之前执行完毕
      async语句:
      • 标准写法:

        async 函数名(){try{}catch(err){}}

      • catch语句:catch统一处理异常输出,即try里有一个error即退出,并执行catch语句
      await语句:
      • 位置:必须在async语句的try语句内
      • 功能:强制同步,有此关键字,await后续语句必须等待此语句执行完毕后才可开始执行
      • 写法:

        let 变量名 = await promise语句

        ,promise语句:可以.then与.catch
    • css部分
      <style scoped>
      	table,td,th{
      	  /* 设置垂直剧中*/
      	  margin: 0 auto;
      	  /* 设置表格框厚度,线型,颜色*/
      	  border:2px solid red;
      	  /* 设置临近表格合并 */
      	  border-collapse: collapse;
      	}
      </style>
                 

上一篇:Vue学习手册(四)-----组件化开发

上一篇:Vue学习手册(六)-----数据共享vuex