Ajax:XMLHttpRequest

Ajax:XMLHttpRequest


XMLHttpRequest

XMLHttpRequest简称 xhr,是浏览器提供的 Javascript 对象,通过它可以请求服务器上的数据资源。 jQuery 中的 Ajax 函数,就是基于 xhr 对象封装出来的。

get

使用xhr发送get请求方法如下:

  1. 创建xhr对象
  2. 调用xhr.open()方法
  3. 调用xhr.send()方法
  4. 监听xhr.onreadystatechange事件

示例:

javascript 复制代码
<script>
  // 1. 创建 XHR 对象
  let xhr = new XMLHttpRequest()
  // 2. 调用 open 函数
  xhr.open('GET', 'https://jsonplaceholder.typicode.com/posts')
  // 3. 调用 send 函数
  xhr.send()
  // 4. 监听 onreadystatechange 事件
  xhr.onreadystatechange = function () {
    if (xhr.readyState === 4 && xhr.status === 200) {
      // 获取服务器响应的数据
      console.log(xhr.responseText)
    }
  }
</script>

事件监听中,包含了三个属性:

  1. xhr.readyStatexhr对象的请求状态
  2. xhr.status:是服务器的响应状态
  3. xhr.responseText:服务器响应的数据

其中readyState取值如下:

状态 含义
0 UNSENT xhr对象已经创建,但是没有open
1 OPENED xhr已经调用open()
2 HEADERS_RECEIVED xhr已经调用send(),并且接收到服务器的响应头
3 LOADING 已经接收到部分响应报文
4 DONE Ajax请求完成,表示请求彻底完成或者失败

DONE时,有可能是请求失败,此时还要检测xhr.status是否成功。

如果在发送get请求时,需要带参数,在open时直接以?key=value的形式追加到url的末尾:

javascript 复制代码
xhr.open('GET', 'https://jsonplaceholder.typicode.com/posts?id=1')

url

这种以?的形式,在地址末尾进行传参,称为查询字符串。把要传递的参数以?key=value的形式追加到末尾,如果有多个参数,参数之间用&分隔:

javascript 复制代码
url?key1=value1&key2=value2&key3=value3

不论是以jQueryAjax,还是xhr,只要发送的是get请求,都是以查询字符串的形式携带参数。

如果发送的请求中,参数包含中文:

javascript 复制代码
xhr.open('GET', 'https://jsonplaceholder.typicode.com/posts?id=1&text=你好世界')

此时中文就会被进行编码:

可以看到,发送除去的请求,text=%....一串带有多个%的乱码,每个%后面是一个两位的十六进制数字,每三个%XX表示一个中文字符。

因为在url中,只允许出现英文字母,标点符号,数字,不允许出现中文,所以中文会被进行特殊编码。

JavaScript提供了方法encodeURIdecodeURI,可以直接进行编码和解码:

javascript 复制代码
<script>
  let str = '你好世界'
  let str2 = encodeURI(str)  // 编码
  console.log(str2)
  let str3 = decodeURI(str2) // 解码
  console.log(str3)
</script>

输出结果:

javascript 复制代码
%E4%BD%A0%E5%A5%BD%E4%B8%96%E7%95%8C
你好世界

第一行是编码结果,第二行是解码结果。


post

使用xhr发送get请求方法如下:

  1. 创建xhr对象
  2. 调用xhr.open()方法
  3. 设置Content-Type属性
  4. 调用xhr.send()方法
  5. 监听xhr.onreadystatechange事件

示例:

javascript 复制代码
<script>
  // 1. 创建 xhr 对象
  var xhr = new XMLHttpRequest()
  // 2. 调用 open 函数
  xhr.open('POST', 'https://jsonplaceholder.typicode.com/posts')
  // 3. 设置 Content-Type 属性
  xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
  // 4. 调用 send 函数
  xhr.send('id=1&text=你好世界')
  // 5. 监听事件
  xhr.onreadystatechange = function () {
    if (xhr.readyState === 4 && xhr.status === 201) {
      console.log(xhr.responseText)
    }
  }
</script>

此处有两个注意点:

  1. 需要通过xhr.setRequestHeader方法设置Content-Type 属性,属性值为application/x-www-form-urlencoded
  2. 传递的参数作为send的参数,多个键值对以&隔开,不再需要?

数据交换格式

所谓数据交换格式,其实就是客户端与服务器之间,数据要以统一的格式进行组织,方便双方进行数据交互,常见的交换格式为XMLjson

XML

XML是一种是一种标记语言,语法格式与HTML非常像。

xml 复制代码
<note>
	<to>李四</to>
	<form>张三</form>
	<heading>通知</heading>
	<body>晚上开会</body>
</note>

以上就是一个XML格式的信息,表示张三给李四发送了一条通知,内容是晚上开会。可以看出,这种格式的数据语义非常明确易懂。

但是XML会有很多额外的空间浪费,比如说以上内容中,标签比数据还多,会显得很臃肿,所以其实json会使用的更多。


json

json全称JavaScript Object Notation,即JavaScript对象表示法,它是由JavaScript推出的一种数据格式化的形式,自然JavaScript本身就对其有很强的解释能力,提供了很多接口完成这样的工作。

json用字符串来表示数组和对象,通过数组与对象的嵌套,其可以表示很多复杂的数据结构。

  • {}:包含一个对象,以key: value的形式,以,分隔各个键值对
  • []:包含一个数组,以,分隔各个元素value

其中,key必须是字符串形式,而value可以指数字、字符串、布尔值、null、数组、对象六种类型。

示例:

json 复制代码
{
	"name": "张三",
	"age": 20,
	"gender": "男",
	"address": null,
	"hobby": ["HTML", "JavaScript", "Java", null]
}

这个json最外层是一个{},表示这是一个对象,对象有五个属性,所有属性的key都是字符串。注意,在json中,所有字符串必须以双引号表示,不能使用单引号。

属性值中20是数字,null表示是空,"张三" "男"都是字符串,而最后一个属性值嵌套了一个数组。

在数组中,无需以key: value的形式存储元素,只存储value,并且可以是六种类型之一。

json 复制代码
[
	666,
	"hello world",
	["HTML", "JavaScript", "Java"],
	{
		"name": "张三",
		"age": 18,
		"hobby": ["西瓜", "桃子", "哈密瓜"]
	}
]

以上json,最外层是一个[],表示这是一个数组,数组无需key,所以四个元素都是单独出现的,前两个元素666"hello world"分别是数字和字符串。第三个元素是数组内嵌套的一个数组,第四个元素是数组内嵌套的一个对象。

而在第四个元素内部,由于是对象,所以又要以key: value的形式填写数据,"hobby"则是数组嵌套对象再嵌套数组,可以一直嵌套下去。

JavaScript提供了方法,可以直接把一个符合要求的字符串转为对象。

语法:

javascript 复制代码
JSON.parse("str")

示例:

javascript 复制代码
let jsonStr = `
{
  "name": "张三",
  "age": 20,
  "gender": "男",
  "address": null,
  "hobby": ["HTML", "JavaScript", "Java", null]
}
`
let obj = JSON.parse(jsonStr)
console.log(obj)

此处jsonStr就是一个符合要求的字符串,通过JSON.parse(jsonStr)将其转化为对象,并输出。

输出结果:

得到了一个属性值和字符串描述一模一样的对象。

当然,以上的json是带有换行格式的字符串,就算把所有内容写在同一行,也可以正常解析:

javascript 复制代码
let jsonStr = '{"name": "张三","age": 20,"gender": "男","address": null,"hobby": ["HTML", "JavaScript", "Java", null]}'

虽然这样json的可读性会降低,但是因为减少了换行,其实传输效率会变高。

如果已有一个对象,也可以通过方法直接转化为json字符串。

语法:

javascript 复制代码
JSON.stringify(obj)

示例:

javascript 复制代码
let obj = {
  name: "张三",
  age: 20,
  gender: "男",
  address: null,
  hobby: ["HTML", "JavaScript", "Java", null]
}

let jsonStr = JSON.stringify(obj)
console.log(jsonStr)

输出结果:

这样就拿到了转化为json字符串格式的对象了,而且默认是不带换行的格式。


XMLHttpRequest Level 2

xhr Level 2xhr的新版本,其提供了更加丰富的功能:

  1. 允许用户设置请求的时间限制
  2. 可以使用FormData管理表单数据
  3. 可以上传文件

请求时限

有的时候网速比较慢,用户要等待很久才能完成一个请求,此时为了避免不必要等待,可以设置请求时限,超出一定时间没有完成请求,直接失败。

其用法很简单,只需要添加一个属性即可:

javascript 复制代码
xhr.timeout = 超时时限

其中时限以毫秒为单位,如果超出时限还没有获取响应,此时直接返回,并触发一个回调函数:

javascript 复制代码
xhr.ontimeout = function(event){}

这个回调函数,只需要设置到ontimeout属性中即可。


表单数据操纵

为了方便表单数据的处理,新增了一个FormData对象,其可以模拟表单的操作,快速完成Ajax表单数据的发送。

流程:

  1. 创建FormData对象
  2. FormData对象添加表单项
  3. 创建xhr对象
  4. xhr.send()时,直接以FormData对象作为参数

示例:

javascript 复制代码
let fd = new FormData()
fd.append('name', "张三")
fd.append('age', 18)

let xhr = new XMLHttpRequest()
xhr.open('POST', '###')
xhr.send(fd)

首先 new FormData()得到一个新的对象,append方法用于添加表单项。通过xhropen方法发送POST请求,随后send内直接把fd发送出去,而不需要考虑表单内容的字符串拼接等操作。

另外的,FormData也可以直接读取表单中的数组,而不用一个个append

示例:

javascript 复制代码
let form = document.querySelector('#form1')
form.addEventListener('submit', function (e) {
  e.preventDefault()

  let fd = new FormData(form)

  let xhr = new XMLHttpRequest()
  xhr.open('POST', '###')
  xhr.send(fd)
})

首先通过querySelector获取到表单的DOM对象,对表单的提交事件绑定函数。

随后在函数内部完成发送表单,先阻止默认事件,随后创建FormData对象,直接在构造时new FormData(form),这样就把表单form的内容直接初始化到了FormData中。随后就可以通过Ajax发送出去了。


文件上传

想要通过Ajax发送文件,使用和表单相同的接口。

流程:

  1. 获取上传文件的标签的DOM对象
  2. 获取DOM对象的files属性
  3. 直接把files添加到FormData
  4. FormData通过xhr发送出去

示例:

javascript 复制代码
<input type="file" id="file1" />
<button id="btnUpload">上传文件</button>

这是两个标签,input标签用于上传文件,button用于提交文件。

javascript 复制代码
<script>
  let btnUpload = document.querySelector('#btnUpload')
  btnUpload.addEventListener('click', function () {

    let files = document.querySelector('#file1').files
    if (files.length <= 0) {
      return alert('没有选择文件!')
    }

    let fd = new FormData()
    // 将用户选择的文件,添加到 FormData 中
    fd.append('file', files[0])

    let xhr = new XMLHttpRequest()
    xhr.open('POST', '###')
    xhr.send(fd)

    xhr.onreadystatechange = function () {
      // ...
    }
  })
</script>

button绑定点击事件,在时间内部完成文件上传。首先获取到input文件上传标签document.querySelector('#file1'),在这个对象的.files属性中,包含了用户上传的文件。

这个.files是一个数组,每个数组元素代表一个用户上传的文件。如果files.length <= 0说明用户没有上传文件,直接返回。

随后新建一个FormData对象,把files[0]添加到表单对象中,也就是把用户上传的第一个文件提交上去,随后通过xhr发送给服务器。要注意的是,上传文件必须通过POST请求。

文件上传也可以通过jQuery来代替xhr完成:

javascript 复制代码
$.ajax({
	method: 'POST',
	url: '###',
	data: fd,
	processData: false,
	contentType: false,
	success: function (res) {
		console.log(res)
	}
})

jQuery发送文件时,通过data属性指定要上传的表单对象,如果表单内部的内容是文件,那么processDatacontentType要设置为false

  • processData:不修改Conten-Type属性,使用FormData默认值
  • contentType:不对数据进行编码,以原本的数据格式发送出去(防止文件格式错误)

相关推荐
2301_7965125216 小时前
使用状态管理、持久化存储或者利用现有的库来辅助React Native鸿蒙跨平台开发开发一个允许用户撤销删除的操作
javascript·react native·react.js
全马必破三16 小时前
浏览器原理知识点总结
前端·浏览器
零Suger16 小时前
React 组件通信
前端·react.js·前端框架
LYFlied16 小时前
【每日算法】 LeetCode 394. 字符串解码
前端·数据结构·算法·leetcode·面试·职场和发展
前端不太难16 小时前
RN Navigation vs Vue Router 的架构对比
javascript·vue.js·架构
硕子鸽17 小时前
UniApp + Dify 实战:详解 SSE 流式响应的解析与前端渲染
前端·uni-app·dify
lxh011317 小时前
复原IP地址
前端·数据结构·算法
小白学大数据17 小时前
Python 爬虫如何分析并模拟 JS 动态请求
开发语言·javascript·爬虫·python
2301_7965125217 小时前
React Native鸿蒙跨平台开发包含输入收入金额、选择收入类别、记录备注和日期等功能,实战react-native-paper组件
javascript·react native·react.js