Ajax XMLHttpRequest & 跨域

208 阅读5分钟

XMLHttpRequest

  • 浏览器内置的一个构造函数

使用 XMLHttpRequest 发起 GET 请求

  • 创建 xhr 对象

  • 调用 xhr.open() 函数

  • 调用 xhr.send() 函数

  • 监听 load 事件, xhr.response

    • 拿到服务器响应回来的数据
 // 1.创建异步对象
        let xhr = new XMLHttpRequest()

        // 2.使用异步对象发起请求:准备好请求报文
        // 2.1 请求行:请求方式和请求url,通过open方法可以设置请求行
        xhr.open('get', 'http://www.itcbc.com:3006/api/getbooks')
        // 2.2 请求头: 编码格式,get方式不需要设置请求头,因为get方式的参数只能在url拼接,它有默认的编码格式:UTF-8
        // 2.3 请求体:传递给服务器的参数,get方式的参数应该在url中拼接,所以get方式没有请求体,但是也需要调用send方法,可以不传递参数或者传递null
        xhr.send(null)

        // 3.使用异步对象接收响应
        // xhr.response:就是响应体
        // 当响应完成了,数据可以使用了,就会自动的触发一个load事件,在这个事件中就可以正确的获取到服务器的响应数据
        xhr.addEventListener('load', function() {
          //  如果不出意外,服务器返回给客户端的数据格式是json格式字符串
          console.log(JSON.parse(xhr.response), typeof JSON.parse(xhr.response))
        })

请求时携带URL参数 或 提交请求体

  • URL参数,只能拼接在 URL 地址 后面
  • 请求体,放到 send() 里面

提交请求体数据,需指定Content-Type头

  • 提交请求体数据,需指定Content-Type头

  • 请求体格式 和 对应的Content-Type值 image.png

 // 创建异步对象
        let xhr = new XMLHttpRequest()

        // 发起请求
        // 请求行:post不能在请求行中拼接参数,否则相当于没有传递
        xhr.open('post', 'http://www.itcbc.com:3006/api/addbook')
        // 请求头:post方式传递普通键值对,需要设置Content-type编码格式,否则后台无法正确的获取到参数
        // xhr.setRequestHeader(
        //   'Content-Type',
        //   'application/x-www-form-urlencoded'
        // )
        xhr.setRequestHeader('Content-Type', 'application/json')
        // 请求体,参数格式与get一样,除非你进行其它的处理
        // xhr.send(
        //   `bookname=${booknameV}&author=${authorV}&publisher=${publisherV}`
        // )
        xhr.send(
          JSON.stringify({
            bookname: booknameV,
            author: authorV,
            publisher: publisherV
          })
        )

        // 接收响应
        xhr.addEventListener('load', function() {
          console.log(JSON.parse(xhr.response))
        })

数据交换格式

服务器端与客户端之间数据传输的格式

  • 两种数据交换格
    • XML(很少用)

    • JSON(主流)

      • 用字符串的方式来表示对象或数组类

JSON 数据

  • 格式有两种

    • 对象格式
    • 数组格式
  • 规则

    • 属性名必须使用双引号包裹
    • 字符串类型的值必须使用双引号包裹
    • JSON 中不允许使用单引号表示字符串
    • JSON 中不能写注释
    • JSON 的最外层必须是对象或数组格式(其他类型也可以,但多数是对象或数组格式)
    • 不能使用 undefined 或函数作为 JSON 的值
  • 对象格式的 JSON 数据

    • 对象格式的 JSON 数据,最外层使用 { } 进行包裹,内部的数据为 "key": "value" 的键值对结构。其中:
    • key 必须使用英文的双引号进行包裹
    • value 的值只能是字符串、数字、布尔值、null、数组、对象类型(可选类型只有这 6 种)

image.png

  • 数组格式的 JSON 数据

    • 数组格式的 JSON 数据,最外层使用 [ ] 进行包裹,内部的每一项数据之间使用英文的 , 分隔。其中:
    • 每一项的值类型只能是字符串、数字、布尔值、null、数组、对象这 6 种类型之一。

image.png

  • 把 JSON 数据转换为 JS 数据

    • 调用浏览器内置的 JSON.parse() 函数,可以把 JSON 格式的字符串转换为 JS 数据

image.png

  • 把 JS 数据转换为 JSON 数据

    • 调用浏览器内置的 JSON.stringify() 函数,可以把 JS 数据转换为 JSON 格式的字符串

image.png

  • 数据交换格式

    • 把真实数据转换为字符串的过程,叫做序列化
    • 把字符串转换为真实数据的过程,叫做反序列化

image.png

封装自己的 Ajax 函数

// {name:'jack',age:20} >> name=jack&age=20转换格式
function parseObjectToString(obj) {
  let arr = []
  for (let key in obj) {
    arr.push(key + '=' + obj[key])
  }
  return arr.join('&')
}

// option.method:请求方式
// option.url:请求地址
// option.params:url参数
// option.data:请求体参数
// success:请求成功之后的回调函数
function ajax({ method, url, params, data, success }) {
  // 1.创建异步对象
  let xhr = new XMLHttpRequest()
  // 2.使用异步对象发起请求
  // 2.1 设置请求行
  if (method.toLowerCase() == 'get' && params) {
    url += '?' + parseObjectToString(params)
  }
  xhr.open(method, url)
  // 2.2 设置请求头
  // 2.3 设置请求体
  // instanceof:判断一个的构造函数是否是某个构造函数,意味着判断对象是否是某个构造函数创建的
  if (data instanceof FormData) {
    // 说明传递了formdata ,不用设置请求头
    xhr.send(data)
  } else if (typeof data == 'object') {
    // 说明传递了一个对象
    xhr.setRequestHeader('Content-Type', 'application/json')
    xhr.send(JSON.stringify(data))
  } else if (typeof data == 'string') {
    // 说明这里传递key=value&key=value
    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
    xhr.send(data)
  } else {
    xhr.send()
  }

  // 3.使用异步对象接收响应
  xhr.addEventListener('load', function() {
    // 调用用户传入的回调函数,且将后台的响应数据做为参数回传
    success(JSON.parse(xhr.response))
  })
}

    <script src="./js/myajax.js"></script>

let btnadd = document.querySelector('.btnadd')

      btnadd.addEventListener('click', function() {
        ajax({
          method: 'post',
          url: 'http://www.itcbc.com:3006/api/addbook',
          data: {
            bookname: '颜色不对',
            author: '宇哥',
            publisher: '黑马程序员'
          },
          success: function(res) {
            console.log(res)
          }
        })
      })

image.png

同源策略 & 跨域

同源指的是两个 URL 地址具有相同的协议、主机名、端口号

例如,下表给出了相对于 www.test.com/index.html 页面的 5 个同源检测结果

image.png

同源策略(英文全称 Same origin policy)是浏览器提供的一个安全功能。浏览器的同源策略规定:不允许非同源的 URL 之间进行资源的交互

突破浏览器跨域限制的两种方案

image.png

  • JSONP

    • JSONP 在底层,用到了 script 标签的 src 属性!
    • script 标签的 src 属性,不受浏览器同源策略的限制
    • 可以把非同源的 JavaScript 代码请求到本地,并执行
    • JSONP 仅支持 GET 请求
  • CORS

    • CORS 是解决跨域数据请求的终极解决方案,全称是 Cross-origin resource sharing。
    • CORS 技术需要浏览器和服务器同时支持,二者缺一不可:
    • 浏览器要支持 CORS 功能(主流的浏览器全部支持,IE 不能低于 IE10)
    • 服务器要开启 CORS 功能(需要后端开发者为接口开启 CORS 功能)
    • 服务器端没有开启 CORS 功能,则客户端无法访问那些跨域的接口
    • CORS 是真正的 Ajax 请求,支持 GET、POST、DELETE、PUT、PATCH 等这些常见的 Ajax 请求方式
    • 只需要后端开启 CORS 功能即可,前端的代码无须做任何改动

防抖 & 节流

  • 防抖(debounce)指的是:频繁触发某个操作时,只执行最后一次

  • 节流(throttle)指的是:单位时间内,频繁触发同一个操作,只会触发 1 次