Ajax 第四天

126 阅读3分钟

Ajax 第四天

请求-响应报文

本质:客户端与服务器通信的过程是基于请求和响应的。

​ 1.请求报文:规定了客户端以什么格式把数据发送给服务器

​ 2.响应报文:规定了服务器以什么格式把数据响应给客户端

作用:方便我们做代码的调试

请求报文-格式

1.请求报文:请求行,请求头,空行和请求体4个部分组成

1651114597282

2.响应报文:状态栏,响应头部,空行和响应体4个部分组成

1651114841844

URL参数

本质:常用的5种请求方式,都可以在URL后面携带请求参数

缺点:敏感信息会直接暴露在地址栏

写法:常用的请求参数有两种写法(第二种先了解)

1651115283205

<script>
	//写法1 get(URL)
      axios.get("http://www.itcbc.com:3006/api/getbooks?appkey=HZD123")
      	.then((result)=>{
            console.log(result);
        })
        
    //写法2 get(URL,{params:参数})
      axios.get("http://www.itcbc.com:3006/api/getbooks",{params:{appkey:`HZD123`}})
        .then((result)=>{
            console.log(result);
        })
</script>

请求体

本质:除了GET请求以外,其他4种常用的请求方式,都可以设置请求体

作用:请求体大小没有限制,所以可以提交大量的数据

写法

1651116662988

<script>
  // 写法1 axios.post(url,参数(对象))
  axios.post("http://www.itcbc.com:3006/api/addbook?appkey=HZD123",{bookname:`黄某`,appkey:`XXX`})
            .then((result)=>{
            console.log(result);
        })

 // 写法2 axios.post(url,参数(字符串))
 axios.post("http://www.itcbc.com:3006/api/addbook?appkey=HZD123",`bookname=黄某&appkey=XXX`)
            .then((result)=>{
            console.log(result);
        })
    
 // 写法3
 axios.post(`http://www.itcbc.com:3006/api/formdata`
            ,formdata)
     		.then((result)=>{
            console.log(result);
        })
</script>

注意:请求的时候,设置了不同格式的请求体,需要一个对应的请求头

1651117556460

http响应状态码

本质:http响应状态码由三位数字组成,用来标识响应成功与否的状态

作用:客户端浏览器根据响应状态码,即可判断这次http请求是否成功

1651117653644

常见的http响应状态码

1651117668484

与业务状态码区分

本质:所处的位置,表示的结果,通用性不同

1.所处的位置不同

​ 在响应头的状态行中所包含的状态码,或者请求列表中的Status

1651127609019

​ 业务状态码在响应体的数据中所包含的状态码,如案例中的code

1651127644100

2.表示的结果不同

​ 响应状态码只能表示这次请求是否成功

​ 业务状态码·表示这次业务处理是否成功

3.通用性不同

​ 响应状态码是由http协议规定的,具有通用性。每个不同的状态码都有标准含义

​ 业务状态码是后端程序员自己定义的,不具有通用性(如聚合,天行,百度等API的接口)

1651127825494

XMLHttpRequest

本质:是浏览器内置的一个构造函数

作用

​ 1.基于new出来的XHR实例对象,可以发起Ajax的请求。

​ 2.axios中的axios.get() .post()等方法都是基于XHR来的,XHR是原生(底层)代码

XHR发起GET请求

实现步骤

1651135959681

<script>
 const xhr = new XMLHttpRequest
 xhr.open(`get`,`http://www.itcbc.com:3006/api/getbooks`)
 xhr.send()
 xhr.addEventListener(`load`,function(){
     console.log(this.response); //默认 是字符串的格式
     const obj = JSON.parse(this.response)// 反序列化
     console.log(obj.data);
 })
</script>

请求时携带URL参数

1651139454960

get方法携带参数

<script>
        const xhr = new XMLHttpRequest
        xhr.open(`get`,`http://www.itcbc.com:3006/api/getbooks?appkey=HZD123`)
        xhr.send()
        xhr.addEventListener(`load`,function(){
            console.log(this.response);
            const obj = JSON.parse(this.response)
            const arr = obj.data
            console.log(arr);
            const html = arr.map((value)=>`<li>${value.bookname}</li>`).join(``)
            document.querySelector(`ul`).innerHTML=html
        })
    </script>

post提交请求体数据时

1.调用xhr.setRequestHeader()函数,指定请求体编码格式

1651139627888

2.当请求体格式不同时,需要指定Content-Type的请求头 1651139724975

对象格式

<script>
        const xhr = new XMLHttpRequest()
        xhr.open(`post`, `http://www.itcbc.com:3006/api/addbook`)

        const data = {
            bookname: '2从入门到精通2',
            author: '我自己',
            publisher: '黑马出版社',
            appkey:`HZD123`
        }

        // 对象格式的参数 也要指定 conten-type
        xhr.setRequestHeader(`Content-type`,`application/json`)
        const str = JSON.stringify(data)
        xhr.send(str) //?

        xhr.addEventListener(`load`,function(){
            console.log(this.response);
        })
</script>

字符串格式

<script>
        
        const xhr = new XMLHttpRequest()
        xhr.open(`post`,`http://www.itcbc.com:3006/api/addbook`)
        //要传递的参数 
        const data = {
            bookname:`黄某奇妙冒险`,
            author:`黄某`,
            publisher:`黄某之家`,
            appkey:`HZD123`
        }

        //把data数据 转换 a=1&b=2
        const usp = new URLSearchParams(data)
        const query = usp.toString()
        console.log(query);

        // a=1&b=2 需要指定 content-type 规定
        xhr.setRequestHeader(`Content-type`,`application/x-www-form-urlencoded`)

        // post请求的参数 只能写在 send()
        xhr.send(query)

        xhr.addEventListener(`load`,function(){
            console.log(this.response);
        })
</script>

FormData形式

<script>
    const inp = document.querySelector(`input`)
    const img = document.querySelector(`img`)
    inp.addEventListener(`change`, function () {
        const file = this.files[0]
        const src = URL.createObjectURL(file)
        img.src = src
        
        const formdata = new FormData()
        formdata.append(`avatar`,file)
        
        const xhr = new XMLHttpRequest()
        xhr.open(`post`,`http://www.itcbc.com:3006/api/formdata`)
        xhr.send(formdata)
        xhr.addEventListener(`load`,function(){
            console.log(this.response);
        })
        
    })
</script>

自封装Ajax

1.根据JQ的Ajax出发,封装属于自己的Ajxa

<script>
    // JQ的代码也是通过封装的 我们跟着这个代码思路自封装
    $.ajax({
            url: `http://www.itcbc.com:3006/api/getbooks`,
            type: `get`,
            data: `appkey=HZD123`,
            success(result) {
                console.log(result);
            }
        })
    
    const option = {
            url: `http://www.itcbc.com:3006/api/getbooks`,
            type: `get`,
            data: `appkey=HZD123`,
            success(result) {
                console.log(result);
            }
        }
        // 我们自己封装一个Ajax函数 来实现ajax上传功能
        ajax(option) // 这是一个函数 调用option里面的属性 实现上传
</script>

2.实现第一步功能 GET 方式 不携带参数

<script>
	function ajax(config) {
            const xhr = new XMLHttpRequest()
            // 因为 元素 Ajxa get 请求 携带参数 只能拼接在 URL 后
            xhr.open(config.type, config.url + `?` + config.data)
            xhr.send()
            xhr.addEventListener(`load`, function () {
                //this.response = 上传的返回值转对象后 = option.success(result)
                const obj = JSON.parse(this.response)
                config.success(obj)
            })
        }
</script>

3.当GET方式 携带参数

<script>
        function ajax({type,url,data=``,success}) {
            const xhr = new XMLHttpRequest()
            xhr.open(type, url + `?` + data)
            xhr.send()
            xhr.addEventListener(`load`, function () {
                const obj = JSON.parse(this.response)
                success(obj)
            })
        }
</script>

4.当GET方式中 data是不同类型时

<script>
	function ajax({ url, type, data = ``, success }) {
            const xhr = new XMLHttpRequest()
            if (typeof data === `object`) {
		data = (new URLSearchParams(data)).toString()
            }
            xhr.open(type, url + `?` + data)
            xhr.send()
            xhr.addEventListener(`load`, function () {
                const obj = JSON.parse(this.response)
                success(obj)
            })
        }
</script>

5.封装POST 方式

​ 判断当前data数据类型:字符串、对象、FormData(之前内容)

<script>
    function ajax({ url, type, data = ``, success }) {
            const xhr = new XMLHttpRequest()
            // get请求类型
            if (type === `get`) {
                if (typeof data === `object`) {
                    data = (new URLSearchParams(data)).toString()
                }
                xhr.open(type, url + `?` + data)
                xhr.send()
                // post请求类型
            } else if (type === `post`) {
                xhr.open(type, url)
                // 判断是不是字符串
                if (typeof data === `string`) {
				xhr.setRequestHeader(`Content-type`, `application/x-www-form-urlencoded`)
                    xhr.send(data)
                    // 判断是不是对象(普通对象和FormData)
                } else if (typeof data === `object`) {
          // 判断 实例和构造函数的关系 实例 instanceof 构造函数 
                    if (data instanceof FormData) {
                        xhr.send(data)
                    } else {
                        xhr.setRequestHeader(`Content-type`, `application/json`)
                        const str = JSON.stringify(data)
                        xhr.send(str)
                    }
                }
            }
</script>

总结:

​ 1.通过今天所学的底层原生Ajax 代码 来封装一个 自己的Ajax上传函数 用JQ的Ajax做参考

​ 2.参照JQ的ajxa代码格式 运用底层的原生Ajax 进行封装使用

​ 3.有传参和不传参两种情况 用默认值+解构思路 进一步优化代码

​ 4.最后把形参.属性名 优化 解构{属性名,data=``(默认值)}

​ 5.data可以是没有参数 可以是字符串 还可以是对象

​ 6.type of 判断是否为对象 运用URLsearcParams/ .toString()转换数据

​ 7.post请求方式 与get不同 所以用if区分 get一部分 post 一部分

​ 8.判断当前data数据类型:字符串、对象、FormData 分别放入相应判断函数内

​ 9.判断字符串类型: typeof 判断实例对应构造函数: 实例 instanceof 构造函数

防抖-节流

节流

本质:指的是单位时间内,频繁触发同一个操作,只会触发1次

1651193758540

<script>
      let isLoadding = false; 
  document.querySelector('button').addEventListener('click', function () {
        if (isLoadding) {
          return;
        }
        isLoadding = true;
        getData();
      });
      function getData(query = '') {
        console.log('请求发送出去');
        axios({
          method: 'get',
          url: 'http://www.itcbc.com:3006/api/getbooks' + query,
        }).then((result) => {
          console.log('数据回来了');
          isLoadding = false;
        });
      }
</script>

应用场景1651194406424

防抖

本质:指的是频繁触发某一个操作,只能执行最后一次

1651194332431

<script>
	let timeId
        keyword.addEventListener(`input`, function (e) {
            clearTimeout(timeId)
            timeId = setTimeout(function () {
                let value = keyword.value.trim()
                let valuePush = `?bookname=${value}`
                getData(valuePush)
            }, 1000)
        })
</script>

应用场景

1651194450397