前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【Vue3+TypeScript】CRM系统项目搭建之 — Axiox 网络请求封装

【Vue3+TypeScript】CRM系统项目搭建之 — Axiox 网络请求封装

作者头像
HelloWorldZ
发布2024-03-20 19:13:25
860
发布2024-03-20 19:13:25
举报
文章被收录于专栏:前端开发前端开发

使用 vue 开发时,频繁使用到了 axios 这个网络请求库,这里对其做一个发起请求时携带参数方式的小结。

一、基本使用

1.1. GET 请求

注意:GET请求无请求体,可以是可以有请求体body的,但是不建议带。

为什么不建议带请求体?

:::details 由文心大模型 3.5 生成

在HTTP协议中,GET请求通常用于请求数据,而POST请求则通常用于提交数据。这是因为GET和POST请求在语义和使用上有一些不同:

  1. 语义上的不同
    • GET请求:通常用于请求数据,它的语义是“获取”或“查询”。浏览器会把GET请求的结果(响应体)直接展示给用户。
    • POST请求:通常用于提交数据,它的语义是“提交”或“更新”。POST请求的结果通常是一个操作的结果,而不是直接展示给用户的数据。
  2. 请求体的处理
    • GET请求:虽然GET请求可以包含请求体(body),但大多数HTTP客户端和服务器在处理GET请求时都会忽略请求体。这是因为GET请求的设计初衷就是为了从服务器获取数据,而不是提交数据。GET请求的查询参数应该放在URL的查询字符串中,而不是请求体中。
    • POST请求:POST请求通常包含请求体,用于提交数据给服务器。服务器会处理POST请求的请求体来获取提交的数据。
  3. 缓存和书签
    • GET请求是幂等的和安全的,这意味着多次执行相同的GET请求应该得到相同的结果,并且不会改变服务器上的任何数据。因此,浏览器通常会对GET请求进行缓存。如果GET请求包含请求体,这可能会导致缓存行为不一致或不可预测。
    • 由于GET请求的URL通常会被浏览器记录在历史记录或书签中,如果URL中包含了敏感信息(这些信息通常应该放在请求体中),那么这些信息可能会被泄露。
  4. URL长度限制
    • 浏览器和服务器通常对URL的长度有一定的限制。如果GET请求包含大量的数据在URL中(通过查询参数),这可能会导致URL超过长度限制。
  5. 安全性
    • 将敏感信息(如密码、私钥等)放在GET请求的URL中是不安全的,因为这些信息可能会被记录在浏览器历史、服务器日志或代理缓存中。这些信息应该通过POST请求放在请求体中,并使用适当的加密和身份验证机制来保护。

综上所述,虽然技术上GET请求可以包含请求体,但出于上述原因,通常不建议在GET请求中包含请求体。在实际开发中,应该根据请求的性质和目的选择合适的HTTP方法,并遵循相应的最佳实践。

:::


1.1.1. 使用 GET 方式进行无参请求

接口

代码语言:javascript
复制
 @GetMapping("/get/getAll")
 public ResResult getAllUser(){
	 List<User> list = userService.list();
	 return ResResult.okResult(list);
 }

请求

代码语言:javascript
复制
 axios({
	 url:'http://localhost:8080/get/getAll',
	 method:'get'
 }).then(res=>{
	 console.log(res.data.data)
 })
1.1.2. 使用 GET 方式请求,参数值直接放在路径中

接口

代码语言:javascript
复制
 @GetMapping("/get/{id}")
 public ResResult getUserById(@PathVariable("id") Long id){
         User user = userService.getById(id);
         return ResResult.okResult(user);
 }

请求

代码语言:javascript
复制
 axios({
	 url:'http://localhost:8080/get/1',
	 method:'get'
 }).then(res=>{
	 console.log(res.data.data)
 })
1.1.3. 使用 GET 方式请求,参数拼接在路径中

拼接方式 ①

使用 ? 进行参数拼接

接口

代码语言:javascript
复制
 @GetMapping("/get")
     public ResResult getUserByIds(@RequestParam("id") Long id){
         User user = userService.getById(id);
         return ResResult.okResult(user);
 }

请求

代码语言:javascript
复制
 axios({
	 url:'http://localhost:8080/get?id=1',
	 method:'get'
 }).then(res=>{
	 console.log(res.data.data)
 })

拼接方式 ②

使用 params 【单个参数】

接口

代码语言:javascript
复制
@GetMapping("/get")
    public ResResult getUserByIds(@RequestParam("id") Long id){
        User user = userService.getById(id);
        return ResResult.okResult(user);
}

请求

代码语言:javascript
复制
 axios({
	 url:'http://localhost:8080/get',
	 params:{
		 id:'2'
	 },
	 method:'get'
 }).then(res=>{
	 console.log(res.data.data)
 })

拼接方式 ③

使用 params 【多个参数】

接口

代码语言:javascript
复制
@GetMapping("/get")
    public ResResult getUserByIds(@RequestParam("id") Long id,@RequestParam("username") String username){
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getUsername,username);
        wrapper.eq(User::getId,id);
        User user = userService.getOne(wrapper);
        return ResResult.okResult(user);
 }

请求

代码语言:javascript
复制
axios({
	url:'http://localhost:8080/get',
	params:{
		id:'2',
		username:'swx'
	},
	method:'get'
}).then(res=>{
	console.log(res.data.data)
})

当 POST 有参请求且是简写时,要以 JSON 格式请求

代码语言:javascript
复制
axios.post('http://localhost:8080/post',"id=2&username=swx").then(res=>{
	console.log(res.data.data)
}).catch(err=>{
	console.log('timeout')
	console.log(err)
})
1.1.4. GET 请求的简写方式

无参时:

代码语言:javascript
复制
axios.get('http://localhost:8080/get/getAll').then(res=>{
	console.log(res.data.data)
}).catch(err=>{
	console.log('timeout')
	console.log(err)
})

有参时:

代码语言:javascript
复制
axios.get('http://localhost:8080/get',{params:{id:'2',username:'swx'}}).then(res=>{
	console.log(res.data.data)
}).catch(err=>{
	console.log('timeout')
	console.log(err)
})
1.2. POST 请求

注意:POST 请求的有参、无参请求与如上的 GET 是一样的,只不过是请求方式名换一下。

如下是 POST 请求简写与传入配置项写法时,关于请求体格式的一点区别:

接口

代码语言:javascript
复制
var express = require('express')
var path = require('path')
var bodyParser = require('body-parser')
const { json } = require('body-parser')
var app = express()


app.use(express.static(path.join(__dirname, 'public')))

app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())


app.get('/a', function(req, res) {
    console.log(req.query)
    res.send({ "id": 1, "name": "张三" })
})



app.listen(3000, function() {
    console.log('app is runing...')
})

请求

写法 ①

如果使用 Axios 的 POST 请求的简写形式,需要将数据以 JSON 格式传递。

代码语言:javascript
复制
axios.post('/a', {
	"id": 5,
	"name": "ssss"
}).then(response => {
	console.log('/a1', response.data)
}, error => {
	console.log('错误', error.message)
})

请求

写法 ②

如果将数据直接作为请求体传递,不需要将数据写成JSON格式。axios会根据请求头的Content-Type自动处理数据格式。

代码语言:javascript
复制
axios({
		method: 'POST',
		url: '/a',
		data: {
			id: 1,
			name: "张三"
		}
	})
	.then(response => {
		console.log('/a', response.data)
		return response.data
	}, error => {
		console.log('错误', error.message)
	})

二、请求失败处理

代码语言:javascript
复制
axios.get('http://localhost:8080/get',{params:{id:'2',username:'swx'}}).then(res=>{
	console.log(res.data.data)
}).catch(err=>{
	console.log('timeout')
	console.log(err)
})

三、axios 并发请求

方式 1

接口

代码语言:javascript
复制
@GetMapping("/get/getAll")
    public ResResult getAllUser(){
        List<User> list = userService.list();
        return ResResult.okResult(list);
    }

@GetMapping("/get/get")
    public ResResult getUserByIdt(@RequestParam("id") Long id){
        User user = userService.getById(id);
        return ResResult.okResult(user);
    }

请求

代码语言:javascript
复制
axios.all([
	axios.get('http://localhost:8080/get/getAll'),
	axios.get('http://localhost:8080/get/get',{params:{id:'1'}})
]).then(res=>{
	//返回的是数组,请求成功返回的数组
	console.log(res[0].data.data),
	console.log(res[1].data.data)
}).catch(err=>{
	console.log(err)
})

方式2:使用spread方法处理返回的数组

代码语言:javascript
复制
<script>
    axios.all([
        axios.get('http://localhost:8080/get/getAll'),
        axios.get('http://localhost:8080/get/get',{params:{id:'1'}})
    ]).then(
        axios.spread((res1,res2)=>{
            console.log(res1.data.data),
            console.log(res2.data.data)
        })
    ).catch(err=>{
        console.log(err)
    })
</script>

四、axios全局配置

代码语言:javascript
复制
axios.defaults.baseURL='http://localhost:8080'; //全局配置属性
axios.defaults.timeout=5000; //设置超时时间

//发送请求
axios.get('get/getAll').then(res=>{
	console.log(res.data.data)
});

axios.post('post/getAll').then(res=>{
	console.log(res.data.data)
});

五、axios实例

代码语言:javascript
复制
//创建实例
let request = axios.create({
	baseURL:'http://localhost:8080',
	timeout:5000
});
//使用实例
request({
	url:'get/getAll'
}).then(res=>{
	console.log(res.data.data)
});

request({
	url:'post/getAll',
	method:'post'
}).then(res=>{
	console.log(res.data.data)
})

六、axios拦截器

axios提供了两大类拦截器:

  • 一种是请求方向的拦截(成功的、失败的)
  • 一种是响应方向的拦截(成功的,失败的)

拦截器作用:

比如:请求之前在请求头加token、强制登录

响应的时候可以进行相应的数据处理

请求拦截器

代码语言:javascript
复制
    //创建实例
    let request = axios.create({
        baseURL:'http://localhost:8080',
        timeout:5000
    });

    //配置axios拦截器
    request.interceptors.request.use(config=>{
        console.log("请求进来了...")
        console.log("请求成功方向")
        console.log(config.data.data)
        //放行请求,这一步很重要,否则报错
        return config;
    },err=>{
        console.log("请求进来了...")
        console.log("请求失败方向")
        console.log(err)
    });

    //如果没有创建实例,则使用以下方式
    //配置axios拦截器
    // axios.interceptors.request.use(config=>{
    //     console.log("请求进来了...")
    //     console.log("请求成功方向")
    //     console.log(config)
    //     //放行请求
    //     return config;
    // },err=>{
    //     console.log("请求进来了...")
    //     console.log("请求失败方向")
    //     console.log(err)
    // });

    //使用实例
    request({
        url:'get/getAll'
    }).then(res=>{
        console.log(res.data.data)
    });

响应拦截器

代码语言:javascript
复制
    //创建实例
    let request = axios.create({
        baseURL:'http://localhost:8080',
        timeout:5000
    });

    //配置axios拦截器
    request.interceptors.response.use(config=>{
        console.log("响应进来了...")
        console.log("响应成功方向")
        console.log(config.data.data)
        //放行响应
        return config;
    },err=>{
        console.log("响应进来了...")
        console.log("响应失败方向")
        console.log(err)
    });

    //使用实例
    request({
        url:'get/getAll'
    }).then(res=>{
        console.log(res.data.data)
    });

七、vue 中封装 axios

封装在request.js中

代码语言:javascript
复制
//导入axios
import axios from 'axios'

//创建axios实例
const service = axios.create({
  baseURL: process.env.VUE_APP_BASE_API,
  timeout: 5000
})


//请求拦截器
service.interceptors.request.use(
  config => {

    if (store.getters.token) {
      config.headers['token'] = getToken()
    }
    //放行请求
    return config
  },
  error => {
    console.log(error)
    return Promise.reject(error)
  }
)


//响应拦截器
service.interceptors.response.use(
  response => {
	//返回的数据
    const res = response.data

    if (res.code !== 200) {
      Message({
        message: res.message || 'Error',
        type: 'error',
        duration: 5 * 1000
      })

      // 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired;
      if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
        // to re-login
        MessageBox.confirm('You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', {
          confirmButtonText: 'Re-Login',
          cancelButtonText: 'Cancel',
          type: 'warning'
        }).then(() => {
          store.dispatch('user/resetToken').then(() => {
            location.reload()
          })
        })
      }
      return Promise.reject(new Error(res.message || 'Error'))
    } else {
      return res
    }
  },
  error => {
    console.log('err' + error) // for debug
    Message({
      message: error.message,
      type: 'error',
      duration: 5 * 1000
    })
    return Promise.reject(error)
  }
)

export default service

哪个模块需要发送请求直接引入即可,将以上实例导入

比如:此模块的所有请求接口:api下的skuInfo.js

代码语言:javascript
复制
//导入axios实例
const api_name = '/admin/product/skuInfo'

export default {

  getPageList(page, limit, searchObj) {
    return request({
      url: `${api_name}/${page}/${limit}`,
      method: 'get',
      params: searchObj
    })
  },

  save(role) {
    return request({
      url: `${api_name}/save`,
      method: 'post',
      data: role
    })
  },

  //新人专享
  isNewPerson(id, status) {
    return request({
      url: `${api_name}/isNewPerson/${id}/${status}`,
      method: 'get'
    })
  },
}

list.vue页面中使用

代码语言:javascript
复制
 //先导入
 import api from '@/api/product/skuInfo'
 ?
 api.getPageList(this.page, this.limit, this.searchObj).then(
         response => {
           debugger
           this.list = response.data.records
           this.total = response.data.total
 ?
           // 数据加载并绑定成功
           this.listLoading = false
         }
       )
     }
 ?
 api.save(this.skuInfo).then(response => {
         if (response.code) {
           this.$message({
             type: 'success',
             message: response.message
           })
           this.$router.push({ path: '/product/skuInfo/list' })
           this.saveBtnDisabled = false
         }
       })
 ?
 //新人专享
 handleNewPersonChange(index, row) {
       api.isNewPerson(row.id, row.isNewPerson).then(response => {
         this.$message({
           type: 'info',
           message: '操作成功'
         })
         this.fetchData()
       })
     }
   }

main.js中引入使用

代码语言:javascript
复制
 import * as API from '@/api'
 ?
 Vue.prototype.$API = API

八、立足当前项目

在这里插入图片描述
在这里插入图片描述

service / index.ts

代码语言:javascript
复制
import { BASE_URL, TIME_OUT } from './config'
import HYRequest from './request'

const hyRequest = new HYRequest({
  baseURL: BASE_URL,
  timeout: TIME_OUT
})

export default hyRequest

service / config / index.ts

代码语言:javascript
复制
// 1.区分开发环境和生产环境
// export const BASE_URL = 'http://coderwhy.dev:8000'
// export const BASE_URL = 'http://codercba.prod:8000'

// 2.代码逻辑判断, 判断当前环境
// vite默认提供的环境变量
// console.log(import.meta.env.MODE)
console.log(import.meta.env.DEV) // 是否开发环境
console.log(import.meta.env.PROD) // 是否生产环境
console.log(import.meta.env.SSR) // 是否是服务器端渲染(server side render)

let BASE_URL = ''
if (import.meta.env.PROD) {
  BASE_URL = 'http://codercba.prod:8000'
} else {
  BASE_URL = 'http://coderwhy.dev:8000'
}

console.log(BASE_URL)

// 3.通过创建.env文件直接创建变量
console.log(import.meta.env.VITE_URL)

export const TIME_OUT = 10000
export { BASE_URL }

service / request / index.ts

代码语言:javascript
复制
import axios from 'axios'
import type { AxiosInstance } from 'axios'
import type { HYRequestConfig } from './type'

// 拦截器: 蒙版Loading/token/修改配置

/**
 * 两个难点:
 *  1.拦截器进行精细控制
 *    > 全局拦截器
 *    > 实例拦截器
 *    > 单次请求拦截器
 *  2.响应结果的类型处理(泛型)
 */

class HYRequest {
  instance: AxiosInstance

  // request实例 => axios的实例
  constructor(config: HYRequestConfig) {
    this.instance = axios.create(config)

    // 每个instance实例都添加拦截器
    this.instance.interceptors.request.use(
      (config) => {
        // loading/token
        return config
      },
      (err) => {
        return err
      }
    )
    this.instance.interceptors.response.use(
      (res) => {
        return res.data
      },
      (err) => {
        return err
      }
    )

    // 针对特定的hyRequest实例添加拦截器
    this.instance.interceptors.request.use(
      config.interceptors?.requestSuccessFn,
      config.interceptors?.requestFailureFn
    )

    this.instance.interceptors.response.use(
      config.interceptors?.responseSuccessFn,
      config.interceptors?.responseFailureFn
    )
  }

  // 封装网络请求的方法
  // T => IHomeData
  request<T = any>(config: HYRequestConfig<T>) {
    // 单次请求的成功拦截处理
    if (config.interceptors?.requestSuccessFn) {
      config = config.interceptors.requestSuccessFn(config)
    }

    // 返回Promise
    return new Promise<T>((resolve, reject) => {
      this.instance
        .request<any, T>(config)
        .then((res) => {
          // 单词响应的成功拦截处理
          if (config.interceptors?.responseSuccessFn) {
            res = config.interceptors.responseSuccessFn(res)
          }
          resolve(res)
        })
        .catch((err) => {
          reject(err)
        })
    })
  }

  get<T = any>(config: HYRequestConfig<T>) {
    return this.request({ ...config, method: 'GET' })
  }
  post<T = any>(config: HYRequestConfig<T>) {
    return this.request({ ...config, method: 'POST' })
  }
  delete<T = any>(config: HYRequestConfig<T>) {
    return this.request({ ...config, method: 'DELETE' })
  }
  patch<T = any>(config: HYRequestConfig<T>) {
    return this.request({ ...config, method: 'PATCH' })
  }
}

export default HYRequest

service / request / type.ts

代码语言:javascript
复制
import type { AxiosRequestConfig, AxiosResponse } from 'axios'

// 针对AxiosRequestConfig配置进行扩展
export interface HYInterceptors<T = AxiosResponse> {
  requestSuccessFn?: (config: AxiosRequestConfig) => AxiosRequestConfig
  requestFailureFn?: (err: any) => any
  responseSuccessFn?: (res: T) => T
  responseFailureFn?: (err: any) => any
}

export interface HYRequestConfig<T = AxiosResponse> extends AxiosRequestConfig {
  interceptors?: HYInterceptors<T>
}
本文参与?腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2024-03-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客?前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与?腾讯云自媒体分享计划? ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、基本使用
    • 1.1. GET 请求
      • 1.1.1. 使用 GET 方式进行无参请求
      • 1.1.2. 使用 GET 方式请求,参数值直接放在路径中
      • 1.1.3. 使用 GET 方式请求,参数拼接在路径中
      • 1.1.4. GET 请求的简写方式
    • 1.2. POST 请求
    • 二、请求失败处理
    • 三、axios 并发请求
    • 四、axios全局配置
    • 五、axios实例
    • 六、axios拦截器
    • 七、vue 中封装 axios
    • 八、立足当前项目
    相关产品与服务
    多因子身份认证
    多因子身份认证(Multi-factor Authentication Service,MFAS)的目的是建立一个多层次的防御体系,通过结合两种或三种认证因子(基于记忆的/基于持有物的/基于生物特征的认证因子)验证访问者的身份,使系统或资源更加安全。攻击者即使破解单一因子(如口令、人脸),应用的安全依然可以得到保障。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
    http://www.vxiaotou.com