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:不对数据进行编码,以原本的数据格式发送出去(防止文件格式错误)

相关推荐
开心工作室_kaic42 分钟前
ssm010基于ssm的新能源汽车在线租赁管理系统(论文+源码)_kaic
java·前端·spring boot·后端·汽车
Python私教43 分钟前
Flutter颜色和主题
开发语言·javascript·flutter
大力水手~2 小时前
css之loading旋转加载
前端·javascript·css
Nguhyb2 小时前
-XSS-
前端·xss
前端郭德纲2 小时前
深入浅出ES6 Promise
前端·javascript·es6
就爱敲代码2 小时前
ES6 运算符的扩展
前端·ecmascript·es6
天天进步20153 小时前
Lodash:现代 JavaScript 开发的瑞士军刀
开发语言·javascript·ecmascript
王哲晓3 小时前
第六章 Vue计算属性之computed
前端·javascript·vue.js
假装我不帅3 小时前
js实现类似与jquery的find方法
开发语言·javascript·jquery
究极无敌暴龙战神X3 小时前
CSS复习2
前端·javascript·css