JavaScript 网络编程(二)
AJAX 发送网络请求
发送网络请求基本流程
发送AJAX网络请求的步骤
- 第一步创建网络请求的 AJAX 对象(XMLHttpRequest)
- 第二步监听XMLHttpRequest 状态的变化,或者说 onload 事件(请求完成时触发请求)
- 第三步配置网络请求(通过我们的 open 方法实现打开)
- 第四步发送send网络请求
该请求方式的话是可以实现的是我们的发送 JSON | XML | HTML | text 文本等格式的发送和接收数据的
// 开始实例化发送请求的实例对象
const xhr = new XMLHttpRequest()
// 开始进行监听对象的改变(宏任务中的,发送了实时的请求后,就来实现回调这个函数)
xhr.onreadystatechange = () => {
// 先判断响应状态码
if (xhr.readyState === 4 && xhr.status === 200) {
console.log(JSON.parse(xhr.response))
console.log(JSON.parse(xhr.response)?.data?.banner)
}
}
// 开始实现网络请求的配置
/**
* method 实现请求的方式
* url 发送请求的地址
*/
xhr.open("GET", "url")
// 实现发送网络请求
xhr.send()
XMLHttpRequest readyState状态监听
在我们实现发送网络请求的时候,状态的变化一共是五次的变化,但是有一次的状态变化,我们是可以不用进行监听的
值 状态 描述 0 unsent 代理被创建了,但是还没有使用 open() 方法 1 opened open() 方法已经被调用 2 headers_received send() 方法已经被调用,并且头部和状态已经可获得 3 loading 下载中,responseText 属性已经包含了部分数据 4 done 下载操作已经完成
所以说我们现在就可以使用我们的
xhr.readyState == XMLHtttpResponse.DONE来进行我们的网络请求的判断,满足条件
- 我们直接进入下一步的操作,否则终止操作即可
同时我们在打开请求的时候,我们的 open 方法可以传递三个参数
第一个参数就是发送请求的方式
第二个参数就是发送请求的后端数据库服务器 API 接口
第三个参数就是是否执行异步请求的操作(默认打开的)
- 异步请求代码执行上来观看的话,就是在我们请求后续的代码是不会被阻塞的
- 同步请求代码执行上来观测的话,就是在我们的请求操作获得结果后,后续的代码才被执行,后续代码直接被阻塞
XMLHttpRequest 其他的监听
- 我们在平时开发中,常常使用的监听是我们的
xhr.onreadystatechange,但是的话实际上还有其他的监听模式的
监听模式 监听描述 loadstart请求开始时候的监听 progress一个数据包到达的监听 abort取消请求的方法 error发生连接错误的监听 load请求成功的监听 timeout请求超时被取消请求的监听 loadend在 load ` error timeout abort` 触发的监听
XMLHttpRequest 响应数据和响应类型设置
如何实现获取我们的响应数据呐???
xhr.response就可以就可以实现获取得到我们的响应数据了,任何数据格式支持xhr.responseText专门用来实现获取的是我们的文本类型的数据xhr.responseXML专门用来实现获取的是 XML 的数据格式但是我们在实现 open() 打开请求的时候,实现的请求配置,就可以在 open() 方法之前实现设置
xhr.responseType该属性默认的是设置为的
text普通的文本,所以说这个时候不管是服务器返回的数据格式是什么
- 都是会被解析为 字符串类型的
但是如果想一开始就是接收的是我们的 JSON 数据的格式
- 我们就需要实现的是我们的通过设置返回值类型来限制我们的解析的
xhr.responseType = "json"- 这样实现进行后,我们就不用在后续通过 JSON.parse 来进行解析字符串了
- 获取得到的数据直接通过 JSON 格式进行解析返回值数据
我们现在的话,我们常见的服务器响应的数据类型都是 JSON 数据格式了
XMLHttpRequest 获取http 响应状态
获取我们的响应请求 Http 的状态码就是通过的是我们的
xhr.status来实现获取响应状态码的一般进行后续的操作的话,我们直接使用
200进行判断即可,200代表的是请求成功的标识通过和 200 的请求对比,我们后面在实现对后续的操作即可
这里来讲一个都比较熟悉的,当我们发送请求的时候,如果出现
404 NOT FOUND的提示,那么就是服务器资源没有找到
- 懂的都懂,哈哈哈!!!都干过类似的事情的!!!
xhr.status >= 200 && xhr.status < 300进行 http 请求状态码的判断
XMLHttpRequest 客户端的传参方式
GET / POST 请求传递参数的形式
GET 请求的
query参数的形式实现传递
- 就是实现的是通过我们的
?实现将我们的请求参数和 url 实现拼接- 然后通过
&将我们的每一个参数进行连接- 传递的数据是用的是我们的键值对的形式传输的,使用的是
=进行连接即可https://www.example.com/get?name=76433&age=18&githubName=juwenzhang/xhr.open("GET", "https://www.example.com/get?name=76433&age=18&githubName=juwenzhang/")POST 请求的
x-www-form-urlencoded格式实现传递数据
xhr.open("POST", "https://www.example.com/get/") // 实现发送网络请求,开始发送我们的请求体设置 xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded") // 告知服务器我们传递的数据类型是什么 xhr.send("name=76433&age=18&githubName=juwenzhang/")POST 请求的
FormData格式进行传递数据
FormData 实际上的话是一个对象,和 form 表单连同使用
form 表单的实现形式的话,可以通过获取得到我们的 form 表单中的每个值,然后进行拼接成
urlencoded即可或者说通过我们的 formdata 实现发送数据也是可以的
new FormData(value)xhr.open("POST", "https://www.example.com/get/") // 实现发送网络请求,开始发送我们的请求体设置 const formData = new FormData(document.querySelectorAll('form')) xhr.send(formData)POST 请求的
JSON格式传递数据
xhr.open("POST", "https://www.example.com/get/") // 实现发送网络请求,开始发送我们的请求体设置 xhr.send(JSON.stringify({ name: "76433", age: 18 }))直接来两个具体的样例吧:
- 这个代码使用的技术栈比较老了,使用的是
Django + Jquery来实现的,而且还是一个烂尾的个人项目- 仓库地址
- 下面的两种方式分别是JSON 传递数据的格式和 FormData 传递数据的格式
AJAX 网络请求封装
/**
* 自定义封装网络请求
* 实际上含有很多的好的封装的网络请求库,这里只是微微练习罢了
* @param {string} url
* @param {string} method
* @param {Object} headers
* @param {number} timeout
* @param {Object} data
* @param {"" | "arraybuffer" | "blob" | "document" | "json" | "text"} dataType
* @param {boolean} is_async
* @param {Function} success
* @param {Function} failure
*/
function http_request_MyAjax({url, method = "GET", headers = {}, timeout = 3000, data = {},
dataType = "json", is_async = true, success, failure} = {}) {
// 返回我们的 Promise 来实现处理返回值结果
return new Promise((resolve, reject) => {
try {
const xhr = new XMLHttpRequest()
// 监听事件
xhr.onload = function() {
if (xhr.status >= 200 && xhr.status < 300) {
success&& success(xhr.response)
resolve({status: xhr.status, statusText: xhr.statusText, response: xhr.response})
} else {
failure&& failure({status: xhr.status, statusText: xhr.statusText})
reject({status: xhr.status, statusText: xhr.statusText, response: xhr.response})
}
}
// 配置信息
xhr.responseType = dataType
xhr.timeout = timeout
// 监听网络超时
xhr.ontimeout = function() {
// 定时取消我们的网络请求
const timer = setTimeout(function() {
xhr.abort()
}, 3000)
reject({status: xhr.status, statusText: xhr.statusText, message: "请求超时 Timeout"})
clearTimeout(timer)
}
// 区分 Get 和 Post 发送请求的方式
if (method.toUpperCase() === "GET") {
// for (const [key, value] of Object.entries(data)) {
// url = url + "?" + key + "=" + value
// }
url += Object.keys(data).map(key =>
`${encodeURIComponent(key)}=${encodeURIComponent(data[key])}`).join("&")
xhr.open(method, url, is_async)
xhr.send()
} else {
xhr.open(method, url, is_async)
if (headers) {
// for (const [key, value] of Object.entries(data)) {
// xhr.setRequestHeader(`${key}`, `${value}`)
// }
Object.entries(headers).forEach(([key, value]) =>
xhr.setRequestHeader(key, `${value}`))
}
xhr.send(JSON.stringify(data))
}
} catch (e) {
reject(e)
}
})
}
上面的代码就是我们自己的网络请求封装函数库,我们不用太注意这个吧,因为全网对网络请求进行封装的博客数不胜数
理解思想即可,这个标题部分看着玩玩就行了!!!
注意自己在封装的时候,不用监听 onerror 事件的,如果监听了,不用使用
try...catch...语句来进行捕获异常使用了
try...catch...来实现捕获了异常,这个时候就不用使用通过 onerror 语句来捕获异常了,二者不可兼得同时这里的话,我们还是通过的是 Promise 来进行处理的我们的结果,这是一个很好的开发思维模式,代码的可读性增强很多很多
Fetch 和 Fetch API
该请求方式的话是早期的 XHR 的替代方案
其返回值是一个 Promise
- 请求发送成功的时候,调用 resolve 回调 then 即可
- 请求发送失败的时候,调用reject 回调catch 即可
在后期的话,自己也不要闹一个笑话,就是 axios 和 ajax 有什么区别???
- 以后自己问了这个问题后,给自己的一个大巴嘴子
- axios 只是对原生的 ajax 请求进行了一定封装的网络请求 JS 库
- 一个封装的网络请求库是无法和我们的原生的东西相比的,不在一个维度
- Fetch 和 Ajax 都是属于浏览器默认给我们提供的原生的网络请求的方式,以后要问就问这二者的不同 😄 😄 😄
Fetch函数的基本使用
Fetch(input, [init])input 定义需要获取的资源地址url,这里的话是可以输入对应的 url 地址或者说是 一个 Request 对象
init 表示的就是我们的初始化参数
- method 请求方式的初始化
- headers 配置型文件的定义
- body 请求的 body 信息
先来一个 Get 请求
// 使用我们的 Fetch 发送一个get 请求 /** * 为实现优化的fetch 请求 */ fetch("https://www.google.com/search/").then((response) => { console.log(response) // 首先实现获取得到我们的 response const res = response // 获取具体的返回值结果 res.json().then(data => { console.log(data) }) }).catch((error) => { console.log(error) }) /** * 优化后的fetch 请求 * @return {Promise<void>} */ async function getDate() { const res = await fetch("https://www.google.com") const data = await res.json() console.log(data) }实现一个 Post 请求
async function getData() { const formData = new FormData() formData.append('email', document.getElementById('email').value) formData.append('password', document.getElementById('password').value) formData.append('password_confirmation', document.getElementById('password_confirmation').value) const res = await fetch("https://jsonplaceholder.typicode.com/posts/1", { method: "POST", headers: { "Content-Type": "application/json", }, // 传递参数的时候,向服务器提交的数据 body: JSON.stringify(formData) }) console.log(res.status, res.statusText, res.ok) return await res.json() } getData().then((res) => { console.log(res) }).catch((err) => { console.log(err) })
- 这里的话,我们个人的话可以实现的是拓展一下上传文件的前端时如何做的
- 同时我们实现上传文件的时候,一般使用的是 xhr 来实现文件的上传,因为 fetch 请求是不会监听文件上传的进度的
- 在文件上传的过程中,我们前端实现的操作实际上是很少的,做的最多的还是我们的后端
- 上传我们的文件的时候,基本上都是使用的是我们的 formData 对象来实现的,这个时候的是:
multipart/formdata- 前端文件上传基本流程简介