介绍
原生JS中请求服务器数据所需XHR详解,虽然用不到但是要足够了解!!!
基于XHR发起GET请求
不带参数
// 1. 创建 XHR 对象
var xhr = new XMLHttpRequest()
// 2. 调用 open 函数
xhr.open('GET', 'http://ajax-api.itheima.net/api/books')
// 3. 调用 send 函数
xhr.send()
// 4. 监听 onreadystatechange 事件
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
// 获取服务器响应的数据
console.log(xhr.responseText)
}
}
在上面状态监听事件中可能会有些迷惑,readyState是什么?status又是什么?
readyState:
status:
在请求完成前,status 的值为 0。 值得注意的是,如果 XMLHttpRequest 出错,浏览器返回的 status 也为 0。
status 码是标准的 HTTP status codes。举个例子,status 200 代表一个成功的请求。如果服务器响应中没有明确指定 status 码,XMLHttpRequest.status 将会默认为 200。
/**
* 输出如下:
*
* UNSENT(未发送)0
* OPENED(已打开)0
* LOADING(载入中)200
* DONE(完成)200
*/
带参数
var xhr = new XMLHttpRequest()
xhr.open('GET', 'http://ajax-api.itheima.net/api/books?id=1')
xhr.send()
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
console.log(xhr.responseText)
}
}
在上图可以看到我们请求的url地址后面跟了?...
我们把它叫做查询字符串
什么是查询字符串
定义:查询字符串(URL参数)是指在URL的末尾加上用于向服务器发送信息的字符串(变量)。
格式:将英文的?
放在URL的末尾,然后再加上参数 = 值
,想加上多个参数的话,使用&
符号进行分隔。以这个形式,可以将向要发送给服务器的数据添加到URL中。
GET请求携带参数的本质
无论使用$.ajax 还是 $.get亦或者JS原生XHR方法请求数据其实本质上都是将查询字符串追加到url后面实现的。
$.get('url?name=小美&age=18', () => {});
// 等价 ↓↑
$.get('url', {name: "小美", age: 18}, () => {});
$.ajax({
method: "GET",
url: "url?name=小美&age=18",
success: () => {}
});
// 等价 ↓↑
$.ajax({
method: "GET",
url: "url",
data: {name: "小美", age: 18},
success: () => {}
});
URL编码与解码
什么是URL编码
URL地址中,只允许出现英文相关的字母、标点符号、数字,因此,在URL地址中不允许出现中文字符。
通俗理解:使用英文符号
表示非英文符
号。
$.get('url?name=小美&age=18', () => {});
// 经过url编码后 ↓
$.get('url?name=%E5%B0%8F%E7%BE%8E&age=18', () => {});
每个汉字经过编码后分别对应三个%
组成的英文字符串
如何进行URI编码与解码
encodeURI()
编码
decodeURI()
解码
const str = '码农张先生'
const str2 = encodeURI(str)
console.log(str2)
console.log('----------')
const str3 = decodeURI('%E5%BC%A0%E5%85%88%E7%94%9F')
console.log(str3)
URL编码的注意事项
由于浏览器会自动对URL地址进行编码操作,因此,大多数情况下,程序员不需要关心URL地址的编码与解码操作。
基于XHR发起POST请求
// 1. 创建 xhr 对象
var xhr = new XMLHttpRequest()
// 2. 调用 open 函数
xhr.open('POST', 'http://www.liulongbin.top:3006/api/addbook')
// 3. 设置 Content-Type 属性 (请求头部)
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
// 4. 调用 send 函数, 同时将数据以字符串的形式提交给服务器
xhr.send('bookname=水浒传&author=施耐庵&publisher=上海图书出版社')
// 5. 监听事件
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
console.log(xhr.responseText)
}
}
POST请求方式且没有使用FormData对象管理表单数据时必须要在open之后send之前设置Content-Type
不知道FormData做什么用?请继续往下看
XHR Level2新特性
设置Http请求时限
实例属性和方法:
XMLHttpRequest
.timeout = 3000; // 请求超时时间,单位ms
.ontimeout(() => {}); // 超时后回调函数
案例演示:
var xhr = new XMLHttpRequest()
// 设置 超时时间
xhr.timeout = 30
// 设置超时以后的处理函数
xhr.ontimeout = function () {
console.log('请求超时了!')
}
xhr.open('GET', 'http://ajax-api.itheima.net/api/books')
xhr.send()
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
console.log(xhr.responseText)
}
}
FormData辅助上传数据
Ajax操作往往用来提交表单数据。为了方便表单处理,HTML5新增了一个FormData对象,可以模拟表单操作:
使用FormData不需要手动设置Content-Type属性
// 1. 通过 DOM 操作,获取到 form 表单元素
var form = document.querySelector('#form1')
form.addEventListener('submit', function (e) {
// 阻止表单的默认提交行为
e.preventDefault()
// 创建 FormData,快速获取到 form 表单中的数据
var fd = new FormData(form)
var xhr = new XMLHttpRequest()
xhr.open('POST', 'http://ajax-api.itheima.net/api/data')
xhr.send(fd)
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
console.log(JSON.parse(xhr.responseText))
}
}
})
FormData可以在new时传入form表单用作初始值或最终要提交的数据,同时也提供了更多方法,例如append()
、delete()
、has()
、get()
、getAll()
、keys()
、values()
等等
参考:MDN | FormData - Web API 接口参考
FormData辅助上传文件
稍微有点长,整个流程
<!-- 1. 文件选择框 -->
<input type="file" id="file1" />
<!-- 2. 上传文件的按钮 -->
<button id="btnUpload">上传文件</button>
<br />
<!-- 3. img 标签,来显示上传成功以后的图片 -->
<img src="" alt="" id="img" width="800" />
<script>
// 1. 获取到文件上传按钮
var btnUpload = document.querySelector('#btnUpload')
// 2. 为按钮绑定单击事件处理函数
btnUpload.addEventListener('click', function () {
// 3. 获取到用户选择的文件列表
var files = document.querySelector('#file1').files
// 这里files是一个伪数组,正常情况下files[0]是上传文件的信息,它还有另外一个属性length
if (files.length <= 0) {
return alert('请选择要上传的文件!')
}
var fd = new FormData()
// 将用户选择的文件,添加到 FormData 中
fd.append('avatar', files[0])
var xhr = new XMLHttpRequest()
xhr.open('POST', 'http://ajax-api.itheima.net/api/file')
xhr.send(fd)
// readyState值改变时调用(执行xhr.abort()后不执行)
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
/* xhr.responseText返回一个json字符串 */
var data = JSON.parse(xhr.responseText)
/* 注意:这里data是服务器那边处理成功响应的数据,具体应根据响应数据来写,
下面代码基本可以忽视,因为当前代码块讲的是如何配合FormData上传文件
*/
if (data.status === 200) {
// 上传成功
document.querySelector('#img').src = 'http://ajax-api.itheima.net' + data.url
} else {
// 上传失败
console.log('图片上传失败!' + data.message)
}
}
}
})
</script>
计算文件上传进度
XMLHttpRequest.upload 属性返回一个 XMLHttpRequestUpload (en-US)对象,用来表示上传的进度。这个对象是不透明的,但是作为一个XMLHttpRequestEventTarget,可以通过对其绑定事件来追踪它的进度。
// 监听文件上传的进度
xhr.upload.onprogress = function (e) {
if (e.lengthComputable) {
// 计算出上传的进度
var procentComplete = Math.ceil((e.loaded / e.total) * 100)
console.log(procentComplete)
// 动态设置进度条
$('#percent').css({"width": procentComplete + "%"}).text(procentComplete + '%')
}
}
// 获取成功后
xhr.upload.onload = function () {
$('#percent').removeClass().addClass('progress-bar progress-bar-success')
}
参考文献:MDN | XMLHttpRequest.upload -Web API
END