重学JavaScript高级(十五): XHR以及Fetch的理解应用

JavaScript XHR、Fetch

服务器端渲染-前后端分离

  • **服务器端渲染:**将html文件在后端,拼接好,将整个文件全部返回给前端
    • 随着目前业务逻辑的复杂度提升,这种开发模式,会导致效率低下
    • 同时,有时候前端页面仅修改一小部分数据,就需要将这个网页全部返回,无疑是对网络造成了部分压力

image.png

  • 由于服务端渲染的弊端,因此有了 前后端分离的开发模式
    • 前端通过静态服务器请求HTML文件,js脚本
    • JS脚本中通过AJAX进行网络请求
    • API服务器中写相应的API请求数据库中的数据

image.png

什么是HTTP协议

  • 在维基百科中的解释

    • 超文本传输协议 是一种分布式、协作式和超媒体信息系统的 应用层协议
    • HTTP是万维网的数据通信的基础,设计HTTP最初的目的是为了提供一种 发布和接收HTML页面的方法
    • 通过 HTTP或者HTTPS协议请求的资源由统一资源标识符来标识
  • HTTP是客户端(用户)和服务端(网站)之间请求和响应的标准

    • 一次HTTP请求主要包括:请求(Request)和响应(Response)
    • 请求:包含请求行、请求头和请求体

    image.png

    • 响应:包含响应行,响应头和响应体

image.png

HTTP的版本

  • HTTP/0.9
    • 发布于1991年
    • 只支持GET请求方法获取文本数据,当时主要是为了获取HTML页面的内容
  • HTTP/1.0
    • 发布于1996年
    • 支持POST、HEAD等请求方法,支持请求头、响应头等,支持更多种数据类型
    • 但是浏览器的每次请求都需要与服务器建立一个TCP连接、请求处理完成后立即断开TCP连接,每次建立连接增加了性能损耗
  • HTTP/1.1(目前使用最广泛的版本
    • 发布于1997年
    • 增加了PUT、DELETE等请求方法
    • 采用持久连接(Connection:keep-alive),多个请求可以共同用一个TCP
  • HTTP/2.0
    • 发布于2015年
  • HTTP/3.0
    • 发布于2018年

HTTP请求方式

image.png

HTTP Request Header

image.png

  • content-type是这次请求携带的数据类型

    • **application/x-www-form-urlencoded:**表示数据被编码成以 ‘&’分割的键值对,同时以=分隔键和值
    • **application/json:**表示一个JSON类型
    • text/plain:表示文本类型
    • application/xml:表示xml类型
    • **multipart/form-data:**表示是上传文件
  • content-length:文件的大小长度,不用手动配置

  • keep-alive

    • http是基于TCP协议的,但是通常在进行一次请求和响应结束后会立即中断
    • 在http1.0中若想保持长连接,需要手动进行设置
    • http1.1中,所有的连接都是默认为connection:keep-alive
  • accept-encoding:告知服务器,客户端支持的压缩格式,服务器会返回相应的压缩格式的文件

  • **accept:**告知服务器,客户端可以接收的文件类型

  • **user-agent:**客户端的相关信息

HTTP Response响应状态码

image.png

AJAX发送请求

AJAX是异步的JavaScript和XML

它可以使用JSON、XML、HTML和text文本等格式发送和接收数据

XHR发送请求

  • 如何来完成AJAX请求
    • 创建网络请求的AJAX对象(使用XMLHttpRequest)
    • 监听 XMLHttprequest对象状态的变化,或者监听 onload事件(请求完成时触发)
    • 配置网络请求(通过 open方法
    • 发送 send网络请求
//创建AJAX对象
let xhr = new XMLHttpRequest();

//监听XMLHttpRequest对象状态的变化
xhr.onreadystatechange = function () {
  console.log(xhr.response);
};

//配置网络请求
//method:get/post/delete
//URL
xhr.open("GET", "http://123.207.32.32:8000/home/multidata");

//发送send网络请求
xhr.send();

XHR状态变化的监听

事实上,我们在一次网络请求中,可以看到XHR的状态发生了很多次的变化

状态描述
0UNSENT代理被创建,但是尚未调用open()方法(不会被监听)
1OPENEDopen()方法已经被调用
2HEADERS_RECEIVEDsend()方法已经被调用,并且头部和状态已经可以获得
3LOADING下载中:reponseText属性已经包含部分数据
4DONE下载操作已经完成
  • 因此我们若想获取请求之后的数据,需要在XHR的状态码为4的时候进行获取(注意此状态码不是HTTP的状态码)
//创建AJAX对象
let xhr = new XMLHttpRequest();

//监听XMLHttpRequest对象状态的变化
xhr.onreadystatechange = function () {
  //这样写,代码阅读性不是很好
  //   if (xhr.readyState !== 4) return;
  //此写法,等同于上面的的写法XMLHttpRequest.DONE代表常量
  if (xhr.readyState !== XMLHttpRequest.DONE) return;
  console.log(xhr.response);
};

//配置网络请求
//method:get/post/delete
//URL
xhr.open("GET", "http://123.207.32.32:8000/home/multidata");

//发送send网络请求
xhr.send();

XHR发送同步请求

XHR发送请求,默认发送的是异步请求,即不会阻塞xhr.send()后面代码的执行

  • 若想让XHR发送的是同步请求,即只有当请求拿到数据之后,才能执行 xhr.send()后面的代码
  • xhr.open()中传入第三个参数 false
  • 但是在实际开发中,使用的都是异步请求
//创建AJAX对象
let xhr = new XMLHttpRequest();

//监听XMLHttpRequest对象状态的变化
xhr.onreadystatechange = function () {
  //这样写,代码阅读性不是很好
  //   if (xhr.readyState !== 4) return;
  //此写法,等同于上面的的写法XMLHttpRequest.DONE代表常量
  if (xhr.readyState !== XMLHttpRequest.DONE) return;
  console.log(xhr.response);
};

//配置网络请求
//method:get/post/delete
//URL
xhr.open("GET", "http://123.207.32.32:8000/home/multidata",false);

//发送send网络请求
xhr.send();

//在这里即可拿到相应的数据
console.log(xhr.response)

XHR其他事件的监听

除了 onreadystatechange还有其他的事件可以监听

  • loadstart:请求开始
  • progress:一个响应数据包到达,此时整个response body都在 response
  • abort:调用 xhr.abort()取消了请求
  • error:发生连接错误:域名解析错误或者跨域
  • load:请求完成
//可以代替onreadystatechange进行数据的监听
xhr.onload = function () {
  console.log(xhr.response);
};
  • timeout:由于请求超时二取消了该请求(默认情况下是0,不会超时,手动设置后会有超时)
  • loadend:在load error timeout 或abort之后触发

XHR响应数据和响应类型

在发送网络请求,接收数据的时候,可以对数据的格式进行设置

  • 通过 xhr.responseType进行设置
  • 不设置的时候,默认为 text格式
//创建AJAX对象

//监听XMLHttpRequest对象状态的变化

//对响应数据格式进行设置
xhr.responseType = "json"

//配置网络请求

//发送send网络请求

XHR获取HTTP状态码

通过xhr.status进行获取状态码,xhr.statusText状态描述

  • 写在 监听XMLHttpRequest对象状态的变化
//创建AJAX对象
let xhr = new XMLHttpRequest();

//监听XMLHttpRequest对象状态的变化
xhr.onreadystatechange = function () {
  //这样写,代码阅读性不是很好
  //   if (xhr.readyState !== 4) return;
  //此写法,等同于上面的的写法XMLHttpRequest.DONE代表常量
  if (xhr.readyState !== XMLHttpRequest.DONE) return;
  if (xhr.status >= 200 && xhr.status < 300) {
    //返回正常数据
    console.log(xhr.response);
  } else {
    //返回相应的错误信息
    console.log(xhr.status, xhr.statusText);
  }
};

//配置网络请求
//method:get/post/delete
//URL
xhr.open("GET", "http://123.207.32.32:8000/home/multidataa");

//发送send网络请求
xhr.send();

XHR传递参数的四种方式

  • GET请求通过querystring进行请求
    • 缺点:使用明文进行传输
//创建AJAX对象
let xhr = new XMLHttpRequest();

//监听状态变化
xhr.onload = function () {
  console.log(xhr.response);
};

//设置响应数据格式
xhr.responseType = "json";

//配置网络请求
//get请求,通过querystring进行参数的传递
xhr.open(
  "get",
  "http://123.207.32.32:1888/02_param/get?name=why&name=18&address=广州市"
);

//发送网络请求
xhr.send();
  • POST请求 x-www-form-urlencoded格式
    • 需要对发送的格式进行设置 xhr.setRequestHeader
//创建AJAX对象
let xhr = new XMLHttpRequest();

//监听状态变化
xhr.onload = function () {
  console.log(xhr.response);
};
//post请求,发送urlencoded
xhr.open("post", "http://123.207.32.32:1888/02_param/posturl");
//告知发送的是什么格式的数据
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");

//发送网络请求
xhr.send("name=why&name=18&address=广州市");

  • POST请求 FormData格式
    • 默认发送的就是 FormData格式的数据,因此不用设置
//HTML中有form表单,直接使用form表单即可
const formEl = document.getElementById("form")

//创建AJAX对象
let xhr = new XMLHttpRequest();

//监听状态变化
xhr.onload = function () {
  console.log(xhr.response);
};
//post请求,发送formData数据
xhr.open("post", "http://123.207.32.32:1888/02_param/posturl");

const formData = new FormData(formEl)

//发送网络请求
xhr.send(formData);
  • POST请求 JSON格式:常用
    • 需要将对象转成JSON字符串
    • 同时告知服务器传递的是什么格式的数据
//创建AJAX对象
let xhr = new XMLHttpRequest();

//监听状态变化
xhr.onload = function () {
  console.log(xhr.response);
};

//设置响应数据格式
xhr.responseType = "json";

//post请求,发送JSON格式数据
xhr.open("post", "http://123.207.32.32:1888/02_param/postjson");

//告知服务器传递的JSON格式数据
xhr.setRequestHeader("Content-type", "application/json");

//发送网络请求,传递JSON字符串
xhr.send(JSON.stringify({ name: "why", age: 18, height: 1.88 }));

XHR过期时间和取消请求

  • 过期时间:xhr.timeout
    • 不设置默认为0,代表没有过期时间
    • 超过了设置的时间,浏览器没有得到相应的数据,就会取消请求
    • 通过 xhr.ontimeout可以进行监听
  • 取消请求:xhr.abort()
    • 通过调用此方法可以取消网络请求
    • 同时可以通过 xhr.onabort监听是否主动取消了网络请求
//创建AJAX对象
let xhr = new XMLHttpRequest();

//监听状态变化
xhr.onload = function () {
  console.log(xhr.response);
};

//设置响应数据格式
xhr.responseType = "json";

//设置过期时间
xhr.timeout = 3000;
//监听过期时间
xhr.ontimeout = function () {
  console.log("时间过期了");
};

//监听取消网络请求
xhr.onabort = function () {
  console.log("网络请求被取消了");
};

//post请求,发送JSON格式数据
xhr.open("get", "http://123.207.32.32:1888/01_basic/timeout");

//发送网络请求,传递JSON字符串
xhr.send();

XHR文件上传的接口演练

<input type="file" id="file" />
<button id="btn">上传</button>

<script>
    //获取元素
    let file = document.getElementById("file");
    let btn = document.getElementById("btn");

    //绑定事件
    btn.onclick = function () {
        //获取上传的文件
        let fileData = file.files;
         //准备上传数据
        let formData = new FormData();
        formData.append("test", fileData[0]);

        //实例化XHR对象
        let xhr = new XMLHttpRequest();

        //监听结果变化
        xhr.onload = function () {
            //获取结果
            console.log(xhr.response);
        };

        //网络请求设置
        xhr.open("POST", "123.207.32.32:1888/02_param/upload");

        //发送网络请求
        xhr.send(formData);
    };
</script>

认识Fetch和Fetch API

可以看作是早期的XMLHttpRequest的替代方案

  • Fetch的返回值是一个promise

    • 因此可以通过.then获取结果
    • 通过.catch获取错误请求
  • 基本使用

//完成网络请求
fetch("http://123.207.32.32:8000/home/multidata").then((response) => {
  console.log(response);
});

//获取具体数据(版本一)
fetch("http://123.207.32.32:8000/home/multidata").then((response) => {
  //返回的数据是json就调用json(),text就调用text()方法
  //该方法也是一个promise,使用.then获取具体内容
  response.json().then((data) => {
    console.log(data);
  });
});

//以上版本的代码,在.then中调用了.then,因此可以进行以下优化
//通过链式调用的方式
fetch("http://123.207.32.32:8000/home/multidata")
  .then((response) => {
    //返回的数据是json就调用json(),text就调用text()方法
    return response.json();
  })
  .then((data) => {
    console.log(data);
  });

//以上代码依旧可以做出优化,使用async/await
async function getData() {
  let response = await fetch("http://123.207.32.32:8000/home/multidata");
  let data = await response.json();
  console.log(data);
}

getData();
  • 在发送网络请求中后,response中可以查看HTTP请求状态
 console.log(response.status, response.ok, response.statusText);//200 true "OK"

post请求有参数

使用post请求,默认传递的是formData格式的数据,因此传递其它格式的数据需要进行设置

async function getData() {
  let response = await fetch("http://123.207.32.32:1888/02_param/postjson", {
      //设置请求方法
    method: "post",
      //设置请求头
    headers: {
      "Content-type": "application/json",
    },
      //设置请求体
    body: JSON.stringify({ a: 100 }),
  });
  let data = await response.json();
  console.log(data);
}

getData();
  • 22
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值