JavaScriptXHR&FETCH


XHR就是XMLHttpRequest,Fetch

前端数据请求方式

服务器端渲染

890

在早期的时候,页面都是由后端服务器渲染出来的,用户请求网址后,服务器端需要请求数据库拿到数据,提供jsp等技术把网页渲染组装完成,然后再发送给用户。

这样的话就太麻烦了,后端的工作量也非常的大。所以有了前后的分离。

通俗说就是用户请求页面后,服务器会从数据库拿到数据,然后提供jsp等模板配合数据渲染成一个html页面,然后把组装完成的完整页面返回给用户

前后的分离过程

891

前后端分离的方式就是客户端渲染,用户请求页面后,静态资源服务器会返回静态的html和js脚本等但是没有数据给客户端,然后客户端也就是浏览器会执行js,然后会请求后端服务器从数据库拿到数据后返回给客户端,客户端进行数据和静态页面的整合。

tip:

1-一些小项目,没有前端服务器,静态html,js和后端服务器放在一起。

2-提供数据的后端服务器也叫做api服务器

3-前端总说什么api接口,其实就是后端程序员写的程序,这个接口是给我们数据的,我们通过js去请求接口。

4-执行js去请求后端数据的时候,这个js就是fetch这些

前后的分离优势

892

服务器渲染的缺点:一点点数据发生变化,需要刷新页面重新请求,服务器端重新渲染一次整个页面,然后再把整个页面发送给客户端,会浪费很多资源和性能。

AJAX以前是指异步的JavaScript和XML,但是现在基本上数据不用XML传输,而是用JSON(JSON的全称是JavaScript Object Notation)notation符号的意思,代替,它可以实现不刷新页面,修改变化的一些数据

例子:比如qq空间等网页最下面的 ‘加载更多’ ,你点击一下会出现更多内容,但是页面并不会刷新,因为异步请求的原因,也不会影响到现有内容的使用,比如你加载更多的时候卡住了,照样可以看qq空间的其他东西。(同步任务放在执行栈,异步任务放在任务队列,异步任务不会阻塞同步任务)

但是:现在又流行起了服务器渲染,也就是SSR,后续我也会学。

Http协议的解析

五层协议详解https://blog.csdn.net/yikenaoguazi/article/details/107927588

网络分为五层,应用层,传输层,网络层,链路层,物理层。

http协议和ftp和dns协议处于应用层,传输层有udp和tcp协议,网络层有ip协议

893

1-http最初是用来发布和接收HTML页面的

2-http请求的资源,由url统一资源定位符来标识

3-http的默认端口是80,https的默认端口是443,端口也可以修改

4-https,就是在http上加上了一个安全层证书,SSL安全套接字协议层或者TLS,可以说tls是ssl的升级版。

894

HTTP的组成

895

请求包括请求行,请求头,请求体

响应有响应行,响应头,响应体

请求头

898

content-type可以告诉服务器,我们传输过去的数据是什么格式,方便服务器解析

如content-type:application/json

文本的话就是text/plain (plain平原,朴素的,清楚的)

899

在现在的开发中都用的http1.1,默认开启了一个tcp可以进行多个连接,我们在请求头中需要些connection:keep-alive,这个tcp连接存活时间服务器可以自己设置,node后端服务器

accept-encoding

900

901

accept-encoding是告诉服务器,我这个客户端支持的文件压缩格式,比如请求了一个js文件,服务器可以把这个文件再压缩成更小如gzip格式,就可以降低服务器压力。(这些压缩文件,浏览器支持自动解压)

问题:我们有服务器,我咋给每个js配置个这样的压缩文件?

在后续webpack中,可以设置。

accept

告知服务器可以接收的数据格式,现在一般是*/*
Accept:*/*  也就是说可以接收任意格式
    

accept-encoding一般是请求js这些文件的时候用到,accept是接收数据。

user-agent

这个里面包含了客户端的浏览器版本型号和电脑系统windows还是mac这一类数据。

响应头

903

响应中也有内容长度和内容类型的设置,其中Access-Control-Allow-Origin会涉及到跨域问题,后面会详细学。

http状态码

902

HTTP的版本

896

我们现在最常用的是http1.1版本,多个请求可以共用一个tcp连接

897

参考:https://www.jianshu.com/p/e0b39b52672c

新建一条记录的话就用post,
更新一条记录的话就用put.

put:如果请求URI(Request-URI)指定的的资源已经在源服务器上存在,那么此请求里的实体应该被当作是源服务器关于此URI所指定资源实体的最新修改版本。

put是修改替换了整个数据,patch请求是修改一部分数据。

AJAX发送请求

XHR的基本用法

 <script>
   // 1.创建XMLHttpRequest对象
   const xhr = new XMLHttpRequest()

   // 2.监听状态的改变,也就是说从发送请求变化到得到数据(宏任务)
//这里一样可以用addEventListner事件改成readychange就行了
//为什么这里都是小写?因为事件默认全部小写,如click
	//实际上一次网络请求,这里监听事件触发了四次,有三次为123不满足条件4被return了
   xhr.onreadystatechange = function() {
     // console.log(xhr.response)
     if (xhr.readyState !== XMLHttpRequest.DONE) return

     // 将字符串转成JSON对象(js对象)
     const resJSON = JSON.parse(xhr.response)
     const banners = resJSON.data.banner.list
     //这里拿到数据了,就可以用for循环什么的生成dom对象插入到页面等等操作
     console.log(banners)
   }

   // 3.配置请求open
   // 第一个参数method: 请求的方式(get/post/delete/put/patch...)
   // 第二个参数url: 请求的地址
   xhr.open("get", "http://123.207.32.32:8000/home/multidata")

   // 4.发送请求(浏览器帮助发送对应请求)
   xhr.send()

 </script>

904

一次网络请求中,xhr对象的完成状态readyState发生了多次变化,一共有五种

905

0就是实例了XMLHttpRequest但是还没有open配置

1就是open方法被调用

2就是send方法被调用了,拿到了响应中的响应头

3在下载接口返回的数据了,但是没有下完

4后端接口返回的数据下载完毕

同步和异步请求

在配置open中有第三个参数,默认是true为异步,如果设置为false就会变成同步任务,那么就必须等待完成了这个请求,才能执行后面的代码。

// 3.配置请求open
    // 第一个参数method: 请求的方式(get/post/delete/put/patch...)
    // 第二个参数url: 请求的地址
    xhr.open("get", "http://123.207.32.32:8000/home/multidata",false)

XMLHttpRequest的一些监听事件

906

问题:上面代码的接口返回的本来就是json类型的数据,为什么还要调用JSON.parse()去处理?

907

因为其实XMLHttpRequest对象中有一个responseType属性,如果我们不设置默认为text,就算服务器传过来的是json,在response中也被接收成了文本。

1-当我们接收的是json,可以设置xhr.responseType=’json’

2-当我们接收的是文本,那么我们不能设置xhr.responseType=’json’,就算传来了text,也会提示接收为null,因为底层无法让text转换为json,就会变成null

3-文本可以自动识别转换为xml,无法转换为json;json可以自动识别转换为text和xml;xml可以自动转换为文本,无法转换为json

4-我们也可以直接使用responseXML或者responseText,但是如果使用这两个,也不能设置xhr.responseType=’json’,因为说了接收的是json,你又输出XML/Text也是不行的。

<script>

  // 1.
  const xhr = new XMLHttpRequest()

  // 2.onload监听数据加载完成
  xhr.onload = function() {
    // const resJSON = JSON.parse(xhr.response)
    console.log(xhr.responseXML)
    // console.log(xhr.responseText)
    // console.log(xhr.responseXML)
  }

  // 3.告知xhr获取到的数据的类型
  xhr.responseType = "json"
  // xhr.responseType = "xml"

  // 4.配置网络请求
  // 4.1.json类型的接口
  // xhr.open("get", "http://123.207.32.32:8000/home/multidata")
  // 4.2.json类型的接口
  // xhr.open("get", "http://123.207.32.32:1888/01_basic/hello_json")
  // 4.3.text类型的接口
  // xhr.open("get", "http://123.207.32.32:1888/01_basic/hello_text")
  // 4.4.xml类型的接口
  xhr.open("get", "http://123.207.32.32:1888/01_basic/hello_xml")

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

</script>

获取HTTP请求的网络状态

当然你要等请求完毕才能用这个,不然根本就没有状态码,所以需要监听load事件或者xhr.readyState == XMLHttpRequest.DONE

//我们可以通过xhr.status/xhr.statusText来获取
比如成功,xhr.status会输出200
xhr.statusText会输出“OK”两个字
<script>
  
  // 1.创建对象
  const xhr = new XMLHttpRequest()

  // 2.监听结果
  xhr.onload = function() {
    console.log(xhr.status, xhr.statusText)
    // 根据http的状态码判断是否请求成功
    if (xhr.status >= 200 && xhr.status < 300) {
      console.log(xhr.response)
    } else {
      console.log(xhr.status, xhr.statusText)
    }
  }

  xhr.onerror = function() {
    console.log("onerror", xhr.status, xhr.statusText)
  }

  // 3.设置响应类型
  xhr.responseType = "json"

  // 4.配置网络请求
  // xhr.open("get", "http://123.207.32.32:8000/abc/cba/aaa")
  xhr.open("get", "http://123.207.32.32:8000/home/multidata")

  // 5.发送网络请求
  xhr.send()
</script>

他这里无论请求成功还是失败都会触发onload事件,失败的时候也会触发error事件,status用它们两个监听输出都可以。

GET/POST请求传递参数

其中get会明文显示在地址栏,post请求是把请求放在请求体里面了,记得设置xhr.setRequestHeader(“Content-Type,“application/x-www-form-urlencoded”),不会在地址栏显示

908

方法一

// 1.传递参数方式一: get -> query
     // xhr.open("get", "http://123.207.32.32:1888/02_param/get?name=why&age=18&address=广州市")

把请求写在open的url参数段后面,get?xxxxxxxxx

方式二

// 2.传递参数方式二: post -> urlencoded
    // xhr.open("post", "http://123.207.32.32:1888/02_param/posturl")
    // // 发送请求(请求体body)
    // xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded")
    // xhr.send("name=why&age=18&address=广州市")

open配置中,请求方式改为post,url就写请求的地址,后面不加请求内容

把请求内容写入xhr.send(),记住必须设置请求头的内容类型,否则服务器无法解析识别内容

xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded")

方式三

使用formdata文件传递

<body>

  <form class="info">
    <input type="text" name="username">
    <input type="password" name="password">
  </form>
  <button class="send">发送请求</button>
  
  <script>
    const formEl = document.querySelector(".info")
    const sendBtn = document.querySelector(".send")
    sendBtn.onclick = function() {
      // 创建xhr对象
      const xhr = new XMLHttpRequest()

      // 监听数据响应
      xhr.onload = function() {
        console.log(xhr.response)
      }

      // 配置请求
      xhr.responseType = "json"

      // 1.传递参数方式一: get -> query
      // xhr.open("get", "http://123.207.32.32:1888/02_param/get?name=why&age=18&address=广州市")

      // 2.传递参数方式二: post -> urlencoded
      // xhr.open("post", "http://123.207.32.32:1888/02_param/posturl")
      // // 发送请求(请求体body)
      // xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded")
      // xhr.send("name=why&age=18&address=广州市")

      // 3.传递参数方式三: post -> formdata
      // xhr.open("post", "http://123.207.32.32:1888/02_param/postform")
      // // formElement对象转成FormData对象
      // const formData = new FormData(formEl)
      // xhr.send(formData)

      // 4.传递参数方式四: post -> json
      xhr.open("post", "http://123.207.32.32:1888/02_param/postjson")
      xhr.setRequestHeader("Content-type", "application/json")
      xhr.send(JSON.stringify({name: "why", age: 18, height: 1.88}))
    }
     
  </script>

</body>

也就是说把整个form的dom对象通过(这里必须是form表单类型的dom对象,也可以不写,直接formData.append())

const formData = new FormData(formEl)

转换成了一个FormData对象,然后把这个对象传递给xhr.send(),里面包含的input等内容。这种方法不需要再设置setRequestHeader,因为不设置默认就是form-data方式,这里的xhr.send(formData)就是这种方式。

方法四

传递json格式


// 4.传递参数方式四: post -> json
xhr.open("post", "http://123.207.32.32:1888/02_param/postjson")
xhr.setRequestHeader("Content-type", "application/json")
xhr.send(JSON.stringify({name: "why", age: 18, height: 1.88}))

我们拿到json后需要把它转换为json的字符串,服务器才能识别。为什么这样?因为就是这样设置的,也看后端接口是怎么写的根据情况定。

ajax网络请求封装

一般不用自己封装,我们会使用axios/fetch库,但是我们也需要了解它的底层原理。

作用:我们发送一个网络请求,通常有五步

// 1.创建对象
     const xhr = new XMLHttpRequest()

     // 2.监听数据
     xhr.onload = function() {
    
     }

     // 3.设置类型
     xhr.responseType = "json"

     // 4.open方法
	xhr.open()
//5,发送
    xhr.send()
    
   

一个网页那么多请求,为了重复书写一样的代码,就有了封装,把传递进来的未知内容修改就好了,像个函数一样。

<script>

  // 练习hyajax -> axios
  function hyajax({
    url,
    method = "get",
    data = {},
    headers = {}, // token
    success,
    failure
  } = {}) {
    // 1.创建对象
    const xhr = new XMLHttpRequest()

    // 2.监听数据
    xhr.onload = function() {
      if (xhr.status >= 200 && xhr.status < 300) {
        success && success(xhr.response)
      } else {
        failure && failure({ status: xhr.status, message: xhr.statusText })
      }
    }

    // 3.设置类型
    xhr.responseType = "json"

    // 4.open方法
    if (method.toUpperCase() === "GET") {
      const queryStrings = []
      for (const key in data) {
        queryStrings.push(`${key}=${data[key]}`)
      }
      url = url + "?" + queryStrings.join("&")
      xhr.open(method, url)
      xhr.send()
    } else {
      xhr.open(method, url)
      xhr.setRequestHeader("Content-type", "application/json")
      xhr.send(JSON.stringify(data))
    }

    return xhr
  }

  // 调用者
  hyajax({
    url: "http://123.207.32.32:1888/02_param/get",
    method: "GET",
    data: {
      name: "why",
      age: 18
    },
    success: function(res) {
      console.log("res:", res)
    },
    failure: function(err) {
      // alert(err.message)
    }
  })

  // hyajax({
  //   url: "http://123.207.32.32:1888/02_param/postjson",
  //   method: "post",
  //   data: {
  //     name: "jsondata",
  //     age: 22
  //   },
  //   success: function(res) {
  //     console.log("res:", res)
  //   },
  //   failure: function(err) {
  //     // alert(err.message)
  //   }
  // })

</script>

Timeout和取消请求

我们可以通过xhr.timeout=1000来取消请求,也就是说如果超过了1s服务器没有返回数据,自动取消此请求
也可以通过xhr.abort()来手动取消,比如把它写入一个按钮点击事件
<body>
  
  <button>取消请求</button>

  <script>
    const xhr = new XMLHttpRequest()

    xhr.onload = function() {
      console.log(xhr.response)
    }
    xhr.onabort = function() {
      console.log("请求被取消掉了")
    }
    
    xhr.responseType = "json"
   // xhr.timeout=1000
    // 1.超时时间的设置
    xhr.ontimeout = function() {
      console.log("请求过期: timeout")
    }
    // timeout: 浏览器达到过期时间还没有获取到对应的结果时, 取消本次请求
    // xhr.timeout = 3000
    xhr.open("get", "http://123.207.32.32:1888/01_basic/timeout")

    xhr.send()

    // 2.手动取消结果
    const cancelBtn = document.querySelector("button")
    cancelBtn.onclick = function() {
      xhr.abort()
    }

  </script>

</body>

FetchAPI的使用详解

fetch和axios的区别https://blog.csdn.net/weixin_40016215/article/details/117322523

fetch需要用到promise,这个我原先学的黑马高级里面没有,后续有时间会学习coderwhy老师的2022高级补充

前端文件上传流程

XHR上传

formData.append()方法https://developer.mozilla.org/zh-CN/docs/Web/API/FormData/append

<script>

  // xhr/fetch都可以文件上传,但是fetch无法看到上传进度

  const uploadBtn = document.querySelector(".upload")
  uploadBtn.onclick = function() {
    // 1.创建对象
    const xhr = new XMLHttpRequest()

    // 2.监听结果
    xhr.onload = function() {
      console.log(xhr.response)
    }

    xhr.onprogress = function(event) {
      console.log(event)
    }
    

    xhr.responseType = "json"
    xhr.open("post", "http://123.207.32.32:1888/02_param/upload")

    // 表单
    const fileEl = document.querySelector(".file")
    //这里的files可以拿到那个file类型input的一些数据信息
    const file = fileEl.files[0]

    const formData = new FormData()
    formData.append("avatar", file)

    xhr.send(formData)
  }
</script>

其中XHR中有一个 onprogress里面可以看上传的进度

xhr.onprogress = function(event) {
     console.log(event)
   }

这个event里面包括很多东西,也包括了上传进度

fetch上传

<script>

   // xhr/fetch

   const uploadBtn = document.querySelector(".upload")
   uploadBtn.onclick = async function() {
     // 表单
     const fileEl = document.querySelector(".file")
     const file = fileEl.files[0]

     const formData = new FormData()
     formData.append("avatar", file)

     // 发送fetch请求
     const response = await fetch("http://123.207.32.32:1888/02_param/upload", {
       method: "post",
       body: formData
     })
     const res = await response.json()
     console.log("res:", res)
   }

 </script>

文章作者: 瑾年
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 周东奇 !
免责声明: 本站所发布的一切内容,包括但不限于IT技术资源,网络攻防教程及相应程序等文章仅限用于学习和研究目的:不得将上述内容用于商业或者非法用途,否则一切后果请用户自负。本站部分信息与工具来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。如有侵权请邮件(jinnian770@gmail.com)与我们联系处理。
  目录