网络模块封装


目录
  • jsonp
  • axios
    • axios的使用
    • axios的配置
      • 全局配置
      • 常见配置
  • 框架封装
  • 拦截器

jsonp

  • 在前端开发中,我们一种常见的网络请求方式就是JSONP

    • 使用JSONP最主要的原因往往是为了解决跨域访问的问题
  • JSONP的原理是什么呢?

    • JSONP的核心在于通过script标签的src属性来帮助我们请求数据.
    • 原因是我们的项目部署在domain1.com服务器上时,是不能直接访问domain2.com服务器上的资料的.
    • 这个时候,我们利用script标签的src帮助我们去服务器请求到数据,将数据当作一个javascript的函数来执行,并且执行的过程中传入我们需要的json
    • 所以,封装jsonp的核心就在于我们监听window上的jsonp进行回调时的名称
  • jsonp如何封装呢?

    let count = 1
    export default function originPJSONP(option) {
      // 1. 从传入的option中提取url
      const url = option.url
    
      // 2. 在body中添加script标签
      const body = document.getElementsByTagName('body')[0]
      const script = document.createElement('script')
    
      // 3. 内部产生一个不重复的callback
      const callback = 'jsonp' + count++
    
      // 4. 监听window上的jsonp的调用
      return new Promise((resolve, reject) => {
        try {
          window[callback] = function (result) {
            body.removeChild(script)
            resolve(result)
          }
          const params = handleParam(option.data)
          script.src = url + '?callback=' + callback + params;
          body.appendChild(script)
        } catch (e) {
          body.removeChild(script)
          reject(e)
        }
      })
    }
    function handleParam(data) {
      let url = ''
      for (let key in data) {
        let value = data[key] !== undefined ? data[key] : ''
        url += `&${key}=${encodeURIComponent(value)}`
      }
      return url
    }
    

axios

axios的使用

  • 为什么选择axios?

    • 在浏览器中发送XMLHttpRequests请求
    • 在node.js中发送http请求
    • 支持PromiseAPI
    • 拦截请求和响应
    • 转换请求和响应数据
    • 等等
  • 支持多种请求方式:

    • axios(config)
    • axios.request(config)
    • axios.get(url[, config])
    • axios.delete(url[,config])
    • axios.head(url[, config])
    • axios.post(url[, data[, config]])
    • axios.put(url[, data[, config]])
    • axios.patch(url[, data[, config]])
  • 安装axios

    npm install axios --save
    
  • 使用方式:

    普通方式

    axios({
      //url: 'http://httpbin.org', // 测试网站
      url: 'localhost://8000/menu/multidata',	// 自定义一个springboot的服务器
      method: 'get'				 // 指定提交方式,axios(context)不指定默认为get方式
    }).then(result => {
      console.log(res)
    })
    

    get  / post方式

    axios({
      url: 'http://localhost:8000/menu/queryMenu',
      // 专门针对get请求的一个写法
      params: {
        menuCode: '1'
      }
    }).then(result=>{
      console.log(result);
    })
    axios.post('http://localhost:8000/menu/addMenu',{
      menuCode: 2,
      menuName: '我的',
      order: 2
    }).then(() => {
      console.log('success');
    }).catch(e=>{
      console.log('error');
    })
    

axios的配置

全局配置

  • 在上面的实例中,我们的BaseUrl是固定的

    • 事实上,在开发中很多参数都是固定的
    • 这个时候我们可以进行一些抽取,也可以利用axios的全局配置
    axios.defaults.baseURL = 'http://localhost:8000'
    axios.defaults.timeout = 50
    

常见配置

url、

method: get, post等

baseURL、

transformRequest:[function(data{})] 请求前数据处理、

transformResponse:[function(data){}]请求后数据处理

headers:['x-Request-With':'XMLHttpRequest']自定义的请求头、

params、

paramsSerializer:function(params){} 查询对象序列化函数、

data:{key:'aa'} request body、

timeout、

withCredentials 是否携带token、

adapter:function(resolve, reject, config){} 自定义请求处理、

auth: {userName: '', pwd:''} 身份验证的信息

responseType: '' 响应数据格式:json/blob/document/arraybuffer/texst/stream

框架封装

  • 第一次封装:

    • 将全局配置的"axios.defaults.baseURL = 'http://localhost:8000' "等配置项配置到单独的文件中去

    新建network文件夹,创建index.js

    import axios from "axios";
    
    export function axiosX(config, success, failure) {
      const instance = axios.create({     // 创建axios实例,配置实例的默认配置
        baseURL: 'http://localhost:8000',
        timeout: 5000
      })
      instance(config).then(res => success(res)).catch(err => failure(err))
    }
    

    上面的index.js是通过export一个方法出去,这个方法除了有之前写过的config之外,还传入两个方法,分别是作为成功和失败的回调函数。

    main.js

    import {axiosX} from "@/network";
    axiosX({
      url: '/menu/multidata'
    }, res => {
      console.log(res);
    }, err => {
      console.log(err);
    })
    
  • 第二次封装:

    • 之前时传入三个参数,这次我们只传入一个对象参数,但是这个对象包含了config和succ、err函数

    index.js

    import axios from "axios";
    
    export function axiosX(config) {
      const instance = axios.create({
        baseURL: 'http://localhost:8000',
        timeout: 5000
      })
      instance(config.baseConfig).then(res => {
        config.success(res)
      }).catch(err => {
        config.failure(err)
      })
    }
    

    main.js

    import {axiosX} from "@/network";
    const config = {
      baseConfig: {
        url: '/menu/multidata'
      },
      success: function(res) {
        console.log(res)
      },
      failure: function(err) {
        console.log(err);
      }
    }
    axiosX(config)
    
  • 第三次封装Promise

    • index中,返回Promise,直接在调用时通过then和catch方法处理

    index.js

    import axios from "axios";
    
    export function axiosX(config) {
      return new Promise((resolve, reject) => {
        const instance = axios.create({
          baseURL: 'http://localhost:8000',
          timeout: 5000
        })
        instance(config).then(res => {
          resolve(res)
        }).catch(err => {
          reject(err)
        })
      })
    }
    

    main.js

    import {axiosX} from "@/network";
    axiosX({
      url: '/menu/multidata'
    }).then(res => {
      console.log(res);
    }).catch(err => {
      console.log(err);
    })
    

    但是由于我们instace(config)本身返回值就是一个Promise:

  • index.js的写法进一步优化:

    import axios from "axios";
    
    export default function axiosX(config) {
      const instance = axios.create({
        baseURL: 'http://localhost:8000',
        timeout: 5000
      })
      instance(config)
    }
    

拦截器

  • axios提供了拦截器,用于我们在发送每次请求或者得到相应响应后,进行对应的处理。

    • 请求拦截:
      1. config中的一些信息不符合服务器的要求
      2. 每次发送网络请求时,都希望在界面中显示一个请求的图标
      3. 某些网络请求(比如登录),必须携带一些特殊的信息token
    • 响应拦截:
      1. 过滤我只想得到的信息
      2. 请求图标这个时候可以隐藏掉了
      3. 错误页面的跳转
  • 如何使用拦截器?

    // 配置请求和响应拦截
    instance.interceptors.request.use(config => {
      console.log('来到了request拦截success中');
      return config
    }, err => {
      console.log('来到了request拦截failure中')
      return err
    })
    
    instance.interceptors.response.use(response => {
      console.log('来到了ersponse拦截success中')
      return response.data
    }, err => {
      console.log('来到了response拦截failure中')
      return err
    })