【前端请求】一文总结Ajax、Axios及Fetch

1.Ajax

        Ajax 全称 Asynchronous JavaScript And XML 及异步JS与XML,其主要原理是使用XMLhttpRequest对象完成前后端交互,

它通过状态码readyState区别当前状态,分别为

        0.未定义

        1.载入中

        2.载入完成

        3.交互中

        4.交互完成

可通过状态码改变执行操作,而平时使用的ajax都是封装好的一个程序,他的封装过程如下:

        1.获取请求对象,内部应当包含请求类型,接口url和上传服务器的数据 

        2.新建httpRequest对象  

let xhr = new XMLHttpRequest()

        3.将请求配置参数赋值给httpRequest对象

xhr.open('get', obj.url + toValue(obj.data), obj.isAsync)

        4.发送

xhr.send()

        5.状态更改回调检测到数据返回并执行相应操作

xhr.onreadystatechange = function () {
        if (xhr.readyState === 4) {
         解析后端返回数据
        }
    }

一个简单的ajax封装应当是这样的

        

//封装一个ajax 即XMLHttpRequest

/*
使用说明
以一下格式发送数据
  ajax({
            url: '/login',
            method: 'get',
            data: {
                username:'xh1001',
                password:'T01'
            },
            isAsync: 'true',
            success:function(res){
                console.log("res:",res.data);
            },
            error:function(err){
                console.log("err:",err);
            }
        })
*/


/*分割线************************ */
function ajax(obj) {
    //判断接口是否为空
    if (!obj.url) {
        return;
    }

    //1.数据检查及补充
    //请求种类,默认为get
    obj.method = obj.method || 'get'
    //是否异步,默认为true
    obj.isAsync = obj.isAsync || 'ture'
    //是否有数据,没有默认补充为空对象
    obj.data = obj.data || {}

    // 2.准备ajax
    let xhr = new XMLHttpRequest() || new ActiveXObject()//ie兼容

    // 发送get或者post
    if (obj.method === 'get') {
        // 准备发送数据
        xhr.open('get', obj.url + toValue(obj.data), obj.isAsync)
        // 发送get
        xhr.send()
    } else if (obj.method === 'post') {
        // 准备发送数据
        xhr.open('post', obj.url, obj.isAsync)
        // 配置请求头content-type 申明数据以什么方式解析数据(json)
        xhr.setRequestHeader('Content-type', 'application/json')
        // 配置请求头content-type 申明数据以什么方式解析数据(表单数据)
        // xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded')

        // 发送post(json)
        xhr.send(JSON.stringify(obj.data))
        // 发送post(表单数据)
        // xhr.send(toValue(obj.data))
    }

    // 检测readyState判断是否将数据传回
    xhr.onreadystatechange = function () {
        if (xhr.readyState === 4) {
            if (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) {
                //返回数据已obj的success回调函数输出
                // console.log('====',xhr.responseText);
                // obj.success(JSON.parse(xhr.responseText))
                // obj.success(xhr.responseText)
                // 检测cookie,如果cookie无效将执行
                if (JSON.parse(xhr.responseText).code === 201) {
                    console.log(JSON.parse(xhr.responseText));
                     .....
                } else {
                    obj.success(JSON.parse(xhr.responseText))
                }
            } else {
                obj.error('unknowError')
            }
        }
    }

}


//前端数据拼接为表单格式
const toValue = function (obj) {
    let str = '?'
    for (let key in obj) {
        str += `${key}=${obj[key]}&`
    }
    return str.slice(0, str.length - 1)
}

其中 // xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded')这里的setRequestHeader其实是对请求头进行配置,而Content-type具体是对请求的数据解码方式进行说明,以便后端服务器处理数据,

        常用的有application/x-www-form-urlencoded(原生form表单)、application/json(json数据)、multipart/form-data(带文件上传功能得数据盒子,一个对象)

这样在页面中只要调取ajax({datas})程序 ,就可以发送ajax请求了

当然数据的处理不是一概而论的,所以我们在发送ajax时输入的对象中配置成功或失败的回调(这里只针对返回的数据而言成功与否,并不是对ajax请求)

 ajax({
        url: '/studentCodeChange',
        method: 'post',
        data: {
            id: nowUser.s_id,
            oldCode: oldCode,
            newCode: newCode
        },
        success: function (data) {
            console.log("data", data);
            // 清空输入框
            alert('修改密码成功')
            $('#codeChangeLab').css('display', 'none')
            $('#oldCode').val('')
            $('#newCode').val('')
            $('#reCode').val('')

        },
        error: function (err) {
            console.log('err', err);
            alert('查询失败,请稍后尝试')
        }
    })

2.Axios

axios本身是对ajax而言的一个二次封装,相比原生Ajax,它用到了promise技术,从而改变了ajax需要多次调用时的尴尬,在成功之后我们可以用.then().catch()轻易进行链式调用,使得代码可读性更高,同时promise可以更方便地对请求本身进行修改,从而很好地解决了身份验证,地址传值等处的代码量,我们在使用时可以简单地调用它,也可以进行复杂的逻辑操作。

        一个简答的axios请求是这样的:

const axios= axios.create({
    baseURL: '/api',    // 给axios请求的 url 前面加一个  '/api'
    timeout: 5000,   //整体设置axios的请求超时时间
    // headers: {'X-Custom-Header': 'foobar'}   //整个加请求头
})

axios({
                url: '/SystemSetting/login',
                method:'post',
                data: data
            }).then((res)=>{

                do sth......
            })


axios({
                url: '/SystemSetting/login',
                method:'get',
                params: data
            }).then((res)=>{

                do sth......
            })

正如上面所说的 ,我们可以对axios进行一定的封装,通常封装的目的是

1.配置baseUrl

通常项目开发时,需要跨域,在我们设置了跨域服务器后,请求也需要向对方服务器发送,所以要配置一个变量作为请求头,而这里的baseUrl激素hi为了统一配置方便开发,开发完成后置空或者删除再部署到服务器

2.拦截器配置

axios.interceptors.request.use

3.设置延迟时间

请求不能一直等待,当到达一定时限后要取消发送并返回请求超时

import axios from 'axios'


const http = axios.create({
    baseURL: '/api',    // 给axios请求的 url 前面加一个  '/api'
    timeout: 5000,   //整体设置axios的请求超时时间
    // headers: {'X-Custom-Header': 'foobar'}   //整个加请求头
});

// 以下是拦截器  
//拦截请求   use 接收两个参数  第一个是请求成功的回调函数,第二个请求失败的回调函数
http.interceptors.request.use(function (req) {
    //再整整发起请求前的操作
    // console.log('req',req);
    //如果有token的话,就携带上,没有不携带
    if(localStorage.getItem('token')){
        //携带在请求里面
        req.headers['token'] = localStorage.getItem('token')
    }
    

    return req;  //放行
}, function (error) {
    // Do something with request error
    return Promise.reject(error);
});

//拦截响应
http.interceptors.response.use(function (res) {
    //响应回来 做的操作
    // console.log('相应回来的数据',res);
    
    //存token
    if(res.data.data && res.data.data.token){
        localStorage.setItem('token',res.data.data.token)
    }
    //简写
    // res.data.token && localStorage.setItem('token',res.data.token)
    
    //判断res里面有没有token,有的话就存起来,没有就不管

    return res;  //放行
}, 
function (error) {
    console.log('err111',err);
    //判断一下响应的状态码
    if(error.response.status === 401){
        alert('身份过期 没有携带token')
        //把token清除掉
        localStorage.removeItem('token')
        //跳转到等录取 重新验证身份
    }
    return Promise.reject(error);
}
);





export default http

3.fetch

fetch是基于promise的一个原生语法糖,关于他的用法,官方给出了一个很完善的例子

// Example POST method implementation:
async function postData(url = '', data = {}) {
  // Default options are marked with *
  const response = await fetch(url, {
    method: 'POST', // *GET, POST, PUT, DELETE, etc.请求方式
    mode: 'cors', // no-cors, *cors, same-origin 是否开启代理
    cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached缓存
    credentials: 'same-origin', // include, *same-origin, omit是否同源
    headers: {
      'Content-Type': 'application/json'数据类型
      // 'Content-Type': 'application/x-www-form-urlencoded',
    },
    redirect: 'follow', // manual, *follow, error重定向
    referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
    body: JSON.stringify(data) // body data type must match "Content-Type" header同请求头
//格式
  });
  return response.json(); // parses JSON response into native JavaScript objects
}

postData('https://example.com/answer', { answer: 42 })
  .then(data => {
    console.log(data); // JSON data parsed by `data.json()` call
  });

一般使用的时候还是要封装,我们再举一个简单的封装案例:

function http({url,method,data={},headers={}}){
    console.log(method)
    console.log(data)

    if(!url){
        return
    }

    // 常用请求头
    headers["Content-type"] = "application/json"
    headers["token"] = "token@@@@@"

    if(method.toLowerCase()==="get"){
        data = JSONtoUrl(data)
        console.log("getting")
        let newUrl = url+'?'+data
        let init = {method:"get"}
        return fetch(newUrl,init).then((res)=>{res.json()})
    }else{
        console.log("posting")
        let init = {
            method:"post",
            body:JSON.stringify(data),
            headers
        }
        console.log(init)
        console.log(init.body)
        return fetch(url,init).then((res)=>{res.json()})
    }


}

function JSONtoUrl(json){
    let str = ''

    for(let k in json){
        str += `${k}=${json[k]}&`
    }

    str = str.substring(0,str.length-1)

    return str
}

export default http

这里要注意这一步不能少

.json的作用是将promise对象解析为一个接送对象,官方的说法是fetch返回的是一个完整的http请求的相应格式,并不能直接被我们使用,这里就需要他们设定的json()方法进行解析,由于基于promise,我们直接将其封装在返回值内,这样就可以直接得到后端原本发给我们的数据了。

return fetch(newUrl,init).then((res)=>{res.json()})

封装后发送

 let packageGet = ()=>{
        http({
            url:'x',
            method:'get',
            data:{name:"sss",age:18},
        }).then((res)=>{
            console.log(res)
        })
    }

    let packagePost = ()=>{
        http({
            url:'x',
            method:'post',
            data:{"name":"xxx","age":"18"},
        }).then((res)=>{
            console.log(res)
        })
    }

一个fetch

你可能感兴趣的:(前端必会,javascript,ajax)