文章目录
Ajax概述
Ajax简介:Ajax(Async JavaScript and XML)在网页不刷新的情况下向服务器发送请求,获取响应,实现懒加载的过程
XML简介:XML与HTML类似,都是一种基于标签的标记语言
- HTML的标签都是预定义的,一般用来描述网页
- XML没有预定义标签,标签名都是直接写来用的,一般用来存储数据,曾经的Ajax使用XML传输数据
AJAX的优缺点
- 无需刷新就可以与服务器发送接受请求
- 可以根据用户的事件动态更新页面内容
- 没有浏览历史(无法后退)
- 存在跨域问题(A网站向B网站发送内容)
- 对SEO优化不友好
HTTP协议(详见计算机网络)
规定了浏览器与万维网服务之间的通信,规定了请求与响应,此处主要了解请求与响应报文的格式与参数
- 请求报文结构
- 请求行
- 请求类型: Get/Post/Put…
- URL: /xxx?name=zhangsan&passwd=lisi
- HTTP协议版本: HTTP/1.1…
- 请求头
- Host: www.liukairui.cc
- Cookie: username=admin
- Content-type: text…
- User-Agent: Chrome90
- 空行
- 请求体
- 如果是GET请求,那么请求体是空的
- 如果是POST请求,那么请求体可以是非空的
- 请求行
- 响应报文结构
- 响应行
- HTTP协议版本: HTTP/1.1…
- 响应状态码: 200…
- 响应状态字符串: OK
- 响应头
- Content-type: text…
- Content-encoding: gzip
- Content-length: 1024
- 空行
- 响应体: 例如HTML内容
- 响应行
Chrome查看报文
- F12-Network-选中包
- 对于GET请求,可以看到
- Header选项卡中有四个部分
- General: 请求地址,请求方式,状态码,服务器IP,同源策略
- Response Headers响应头
- Request Headers请求头
- Query String Paramenters将请求url的内容进行解析
- Response: 响应体
- Preview: 预览响应体
- Header选项卡中有四个部分
- 对于POST请求,可以看到
- Header选项卡中有四个部分
- General: 请求地址,请求方式,状态码,服务器IP,同源策略
- Response Headers响应头
- Request Headers请求头
- Query String Parameters: 请求体
- Response: 响应体
- Preview: 预览响应体
- Header选项卡中有四个部分
原生Ajax尝试
Ajax技术可以理解为手动在JS中进行http请求,获取响应报文,根据响应报文修改文件,与之前不同的是,之前是浏览器向服务器发送请求,服务器发送响应,浏览器刷新页面。现在是JS进行请求,JS自己处理结果,我们需要的是一套可以进行Http请求的JSAPI
请求的发送与请求头配置
GET部分
-
服务端配置
服务端使用的是NodeJS,我们需要Express处理http请求,其他的都不需要const express = require("express") var app=express() app.get("/server",(req,res)=>{ // 配置Ajax同源策略,允许跨域访问 res.setHeader('Access-Control-Allow-Origin','*') // 发回响应体 res.send("Wow Ajax working...") }); app.listen(,()=>{ console.log("work on"); })Node代码实现了收到一个/server请求,发回数据,由于但是没有设置页面的路由,我们需要手动打开网页
-
HTML页面
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> </head> <body> <button>发送AJAX</button> <div class="result" style="border:solid;width: 200px;height: 200px;"></div> </body> <script> // 选择元素 const btn = document.querySelector("body > button") var txtbox = document.querySelector(".result") // 绑定事件 btn.onclick=function(){ // 创建对象 const xhr = new XMLHttpRequest(); // 初始化对象http不可以省略 xhr.open('GET',"http://127.0.0.1:9000/server") // 发送请求 xhr.send(); // 当xhr状态发生改变的时候时间 // readystate表示状态分别是 // 0: 没有初始化,1: open结束, 2: send结束, 3: 收到部分结果, 4: 收到所有结构 xhr.onreadystatechange = function(){ if(xhr.readyState===4 && xhr.status >= 200 && xhr.status < 300){ // 打印测试内容 console.log(xhr.status); // 状态码 console.log(xhr.statusText); // 状态字符 console.log(xhr.getAllResponseHeaders()); // 响应头 console.log(xhr.response); // 响应体 // 修改元素 txtbox.innerHTML=xhr.response } } } </script> </html> -
总结
我们使用Ajax实际上就是使用了一系列JS的API,包括四个步骤const xhr = new XMLHttpRequest();创建一个Ajax请求xhr.open('GET',"http://127.0.0.1:9000/server")初始化一个Ajax对象xhr.send();发送这个对象xhr.onreadystatechange绑定对象变化进行操作
我们有几个变量表示对象状态
xhr.readystate: 0: 没有初始化,1: open结束, 2: send结束, 3: 收到部分结果, 4: 收到所有结构xhr.status: 响应状态码xhr.statusText: 响应状态字符xhr.getAllResponseHeaders: 响应头xhr.response: 响应体
POST部分
- 服务端设置
服务端只是把get修改为了postapp.post("/",(req,res)=>{ res.setHeader('Access-Control-Allow-Origin','*') res.send("OK"); }); - HTML设置
事件监听函数内部修改const xhr = new XMLHttpRequest(); xhr.open('POST', "http://127.0.0.1:9000"); // 我们在这里配置我们需要发送的信息 xhr.send('user=Liu&passwd=hey'); xhr.onreadystatechange = function () { ...}
设置请求头
- 设置预定义的请求头
只需要在请求处进行修改,例如xhr.open(...) xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded') xhr.send(...) - 自定义请求头
在HTML部分
此时,出于浏览器安全设置,我们无法发送包,并报错数据头,我们需要修改服务端xhr.open(...) xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded') xhr.setRequestHeader('defMe', 'LiuKaieui') // 举例,参数分别是键值 xhr.send(...)app.all("/",(req,res)=>{ // 其次,由于浏览器会使用get校验服务器权限,所以必须写Get方法,我们直接写成all res.setHeader('Access-Control-Allow-Origin','*') res.setHeader('Access-Control-Allow-Headers','*') // 首先要修改这里,支持所有头 res.send("OK"); });
JSON支持
我们希望服务端向网页传送一个对象,但是默认是不支持的,很容易想到的方法就是服务端把对象转换为JSON,客户端讲JSON字符串转化为对象,有两种方法实现
- 手动实现
服务端只需要讲对象转换为JSON传出即可
网页只需要把收到的对讲转化为对象就可以了(事件监听内部)app.all("/json-server",(req,res)=>{ let tmp = { "name": "Liu","Age": 12}; res.setHeader('Access-Control-Allow-Origin','*') res.send(JSON.stringify(tmp));// 实际上不stringfy也可以 });const rxh=new XMLHttpRequest(); rxh.open("POST","http://127.0.0.1:9000/json-server") rxh.send(); rxh.onreadystatechange=function(){ if(rxh.readyState===4 && rxh.status >=200 && rxh.status <300){ console.log(JSON.parse(rxh.response)); } } - 设置响应头实现
设置响应类型后,我们就不需要手动转换了,浏览器收到JSON字符串后会自动转换,reponse就是一个对象const rxh=new XMLHttpRequest(); rxh.responseType='json'; // 设置响应类型,无需设置header rxh.open("POST","http://127.0.0.1:9000/json-server") rxh.send(); rxh.onreadystatechange=function(){ if(rxh.readyState===4 && rxh.status >=200 && rxh.status <300){ console.log(rxh.response); } }
IE缓存问题
IE(10-)会对Ajax的请求结果进行缓存,会导致下次Ajax请求得到缓存的结果,IE根据请求的url/body进行判断是否使用缓存,我们只需要在请求的时候加一个时间戳("...?t="+Date.now()),很多工具都自动实现了这个功能
请求的取消与重发
超时自动取消
可以制定获取请求的最长时间,超时后浏览器会自动取消请求。方法设置XMLHttpRequest的属性:.timeout: 网络超时时间(ms),.ontimeout: 超时回调函数函数名, .onerror: 网络错误回调函数名
- 设置服务器, 我们设置一个2000ms的延迟模拟网络延时
app.get("/",(req,res)=>{ res.setHeader('Access-Control-Allow-Origin','*') setTimeout(()=>{ res.send("You Get Response")},3000); }) - 设置Ajax函数(事件内部的部分)
var hrx = new XMLHttpRequest(); // 设置超时时间,设置为2000ms的时候必然超时,4000应该不超时 hrx.timeout=4000; // 超时回调函数 hrx.ontimeout=()=>{ alert("Network Too Slow")} // 网络错误回调函数 hrx.onerror=()=>{ alert("Network ERROR")} // 之后一切正常 hrx.open("GET","http://127.0.0.1:9000"); hrx.send(); hrx.onreadystatechange=function(){ if(hrx.readyState === 4 && hrx.status >= 200 && hrx.status < 300){ txtBox.innerHTML=hrx.response } }
手动取消请求
hrx.abord();
就可以直接取消
Ajax 重新发送请求
我们应该设置用户连点的时候取消上一次的请求以减小服务器压力,只要设置一个flag标记是否正在发送即可
jQuery的Ajax
- jQuery有三个函数实现Ajax请求,分别是
$.get(),$.post(),$.ajax() $.get()与$.post()类似,调用方法是$.get( url链接, { 要发送的对象}, (d)=>{ 收到对象的回调函数, d是获取的内容}, "JSON"/"xml"/"html"/"text"/"script"/"json"/"jsonp" //收到数据的类型,例如这里如果写了"JSON",那么服务器发送JSON字符串,这边收到后会自动转换为对象 )$.ajax()是一个通用的方法
参数还有很多,详见文档$.ajax({ // 所有的参数一起是一个对象 url:"http://127.0.0.1:9000", // 请求链接 data:{ "a":100,"b":200}, // 传输数据对象 type:"GET", // 传输方式 dataType:"JSON", // 数据类型 success: (d)=>{ console.log(d)}, // 成功回调函数 error:()=>{ console.log("ERR")}, // 失败回调函数 timeout:2000, // 超时时间 headers:{ // 请求头 可以是标准的,也可以是自定义的 A:100 // 如果是自定义的要在服务端进行设置,见`使用原生...>设置请求头>自定义请求头` } })
get/post使用简单,ajax功能多,按情况使用即可
使用Axios发送Ajax[简易]
是一个热门的AJAX请求库,支持promise, 支持NodeJS,支持取消请求,支持拦截器,简易的使用方式是
axios.get("http://127.0.0.1:9000",{
// 请求地址是一个单独的参数
params:{
// 请求的参数,也就是.com?A=1&b=2那部分,使用Axios你可以不用拼串
id:100,
un:7
},
headers:{
// 自定义请求头
name: 123
},
});
获取请求结果是要使用Promise直接then(), Axios进行post的时候还可以使用params进行链接定制,但是参数列表有所不同axios.post(url,{data对象},{参数对象})
也可以使用axios函数直接发送
// 发送 POST 请求
axios({
method: 'post',
url: '/user/12345',
data: {
firstName: 'Fred',
lastName: 'Flintstone'
}
});
详见官方文档
使用fetch发送请求
fetch是一个window的对象,可以发送Ajax请求,返回一个Promise对象,fetch是前端发展的一种新技术产物。可以简单的理解为是XMLHttpRequest的参数简化版
Fetch API 提供了一个 JavaScript接口,用于访问和操纵HTTP管道的部分,例如请求和响应。它还提供了一个全局 fetch()方法,该方法提供了一种简单,合理的方式来跨网络异步获取资源。这种功能以前是使用 XMLHttpRequest实现的。Fetch提供了一个更好的替代方法,可以很容易地被其他技术使用,例如 Service Workers。Fetch还提供了单个逻辑位置来定义其他HTTP相关概念,例如CORS和HTTP的扩展。fetch代表着更先进的技术方向,但是目前兼容性不是很好,在项目中使用的时候得慎重。
格式是fetch(input[, init]);
- input写url/requert对象
- init写配置对象,有(详见文档)
- method: 请求使用的方法,如 GET、POST。
- headers: 请求的头信息,形式为 Headers 的对象或包含 ByteString 值的对象字面量。
- body: 请求的 body 信息:可能是一个 Blob、BufferSource (en-US)、FormData、URLSearchParams 或者 USVString 对象。注意 GET 或 HEAD 方法的请求不能包含 body 信息。
- mode: 请求的模式,如 cors、 no-cors 或者 same-origin。
fetch('http://example.com/movies.json')
.then(function(response) {
return response.json();
})
在使用fetch的时候需要注意:
- 当接收到一个代表错误的 HTTP 状态码时,从 fetch()返回的 Promise 不会被标记为 reject, 即使该 HTTP 响应的状态码是 404 或 500。相反,它会将 Promise 状态标记为 resolve (但是会将 resolve 的返回值的 ok 属性设置为 false ),仅当网络故障时或请求被阻止时,才会标记为 reject。
- 默认情况下,fetch 不会从服务端发送或接收任何 cookies, 如果站点依赖于用户 session,则会导致未经认证的请求(要发送 cookies,必须设置 credentials 选项)。
Ajax跨域
同源策略是网景提出的浏览器安全策略,他要求Ajax请求的网页与目标服务器url,端口,协议是一致的,Ajax默认遵守这个策略,违背同源就是跨域
JSONP解决跨域问题
JSONP是一个非官方的跨域解决方案,只支持GET请求,利用了<script>标签的特性实现跨域,HTML的很多标签本身就是支持跨域的,例如<img>,<script>会引用外部的文件
首先要在浏览器中定义一个函数用于更新内容,例如我想在跨域请求后将结果更新到#box上
function process_JSONP(t){
$("#box").text(t)
}
跨域被请求端设置(请求端为127.0.0.1)
app.get("/jsonp-server",(req,res)=>{
str = JSON.stringfy({
"name":"我是一个被请求的对象"})
res.send(`process_JSONP(${
str})`); // JS拼串
})
请求端在process_JSONP定义后引用JS
<script src="http://127.0.0.1/jsonp-server">
这样,服务端返回字符串被当作了js,执行了process_JSONP()命令,对网页进行了更新
原生JSONP实例
我们想要实现的功能是,点击#A,浏览器发送跨域请求,服务器发送结果,收到结果后,如果是true,更新.stat背景色为绿色,否则为红色
前端JS设置
function process_jsonp(stat){
// 获取后的处理函数
if(stat)document.querySelector(".stat").style = "background-color:#bfa;"
else document.querySelector(".stat").style = "background-color:#f11;"
}
btnA = document.querySelector("#A");
btnA.onclick=()=>{
const jsLab = document.createElement("script"); // 创建一个script标签
jsLab.src = "http://127.0.0.1:9000/jsonp"; // 设置一个script标签的src
document.body.appendChild(jsLab) // 将script标签添加到网页
}
后端只返回true
因为我们只能写url,不能指定请求头,请求体,我们只能实现get请求
jQuery实现JSONP实例
jQuery的get/post函数默认当然是不支持跨域的,但是jQuery还有一个getJSON函数,这个函数本来是用来请求JSON,但是这个函数在jQuery底层实现的时候是先对参数的url进行解析,然后使用了上面这种script标签的方法获取JSON对象,所以这个方法是支持跨域的,我们可以利用这个特性。
首先了解函数功能,参数列表是getJSON(url,callbackFunction),当函数发现url字符串有callback=?,他会自动替换成callback=一个字符串,之后jQuery会注册一个名字叫这个字符串的方法,这个方法内容就是第二个参数于是我们利用这个特性实现JSONP
我们的目标是: 前端点击#A,后端发回消息,前端将.stat的内容替换为响应结果
前端代码
$("#A").click(()=>{
$.getJSON("http://127.0.0.1:9000/jsonp?callback=?",(d)=>{
// 这里callback=?会在请求的时候被替换
$(".stat").text(d)
})
})
后端代码
app.get("/jsonp",(req,res)=>{
let cb = req.query.callback; // 获取请求中的随机子复查u年
res.send(`${
cb}("Wow You Get!")`); // 调用函数
})
当然这个方法是不适合大量数据请求的
CORS解决跨域问题
CORS(Cross-Origin Resource Sharing,跨域资源共享)是一种官方的跨域解决方案,不需要在客户端进行任何操作,在服务端进行修改就可以直接支持get/post
只需要在服务器上加上响应头Access-Control-Allow-Origin: *即可,如果想要设置允许特定的跨域请求,例如只允许127.0.0.1:5050的,那么只需要修改为Access-Control-Allow-Origin: 127.0.0.1:5050
实例
#btnB点击console显示获取的跨域结果
前端JS
btnB.onclick = ()=>{
const xhr = new XMLHttpRequest();
xhr.open("GET","http://127.0.0.1:9000/jsonp");
xhr.send();
xhr.onreadystatechange=()=>{
if(xhr.readyState === 4 && xhr.status >=200 && xhr.status<300)
console.log(xhr.response)
}
}
后端JS
app.get("/jsonp",(
本文详细介绍了Ajax技术,包括原生Ajax的使用、jQuery的Ajax、Axios库的应用以及Fetch API的使用。重点探讨了Ajax的跨域问题,通过JSONP和CORS两种解决方案进行阐述。此外,还深入分析了Axios的源码,包括其目录结构、请求发送函数、请求取消函数和拦截器的实现。最后,通过一个简易版的axios实现,帮助读者更好地理解Ajax的工作原理。
最低0.47元/天 解锁文章
1295

被折叠的 条评论
为什么被折叠?



