前后端交互基础ajax(一)
ajax
ajax是:Ajax 即“Asynchronous Javascript And XML”(异步 JavaScript 和 XML。是前后端数据交互的数据的一种方式。
ajax基本使用
提交的时候阻止跳转,截取信息下来提交给后端。
它依赖的对象是xmlhttprequest
-
新建XMLHttpRequest对象;
let xhr = new XMLHttpRequest(); -
配置请求参数
xhr.open("get","/checkUser",true); //true是异步,false是同步 -
接收服务器端的返还值
前后端数据ajax交互,服务器发送给客户端的信息的是json我们需要进行一个JSON.parse 转成object
xhr.onload = function(){ let res = JSON.parse(xhr.responseText); } -
发送服务器
xhr.send();
用户登录例子(get方法)
模块依赖,koa koa-static-cache koa-router
后端服务器
router.get("/checkUserName",(ctx,next)=>{
console.log(ctx.query.username);
let res = usersData.find(v=>v.username==ctx.query.username);
if(res){
ctx.body = {
status:1,
info:"用户名正确"
};
}else{
ctx.body = {
status:2,
info:"用户名错误"
};
}
})
前端处理
//失去焦点
document.querySelector(".inputStyle").onblur = function () {
// console.log(this.value);
let xhr = new XMLHttpRequest();
xhr.open("get", `/checkUserName?username=${this.value}`, true);
xhr.onload = function () {
console.log(xhr.responseText);
let obj = JSON.parse(xhr.responseText);
document.querySelector(".exchange").innerHTML = obj.info;
if (obj.status == 1) {
document.querySelector(".exchange").style.color = "green";
} else {
document.querySelector(".exchange").style.color = "red";
}
}
xhr.send();
}
ajax的get请求
url 带参
-
动态路由,参数是必要要填的
/getusername/:id
url: /getusername/参数(1,2,3,4....)
-
queryString (get post 都可以使用)
/getusername
url: /getusername?username=xxxxx&username=xxxxx。返回后端的是username=xxxxx&username=xxxxx 的一个对象
ajax的post请求
post 是通过http 正文传参。后端方面,需要对于post 数据设置编码格式
发送数据时候需要设置http正文头格式;
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded"); //默认编码
xhr.setRequestHeader("Content-type","multipart/form-data"); //二进制编码
xhr.setRequestHeader("Content-type","application/json"); //json编码
设置成json需要编码一下
let obj = JSON.parse({name:xxxx});
node服务器
接收需要用一个Koa-body库,Koa-body当作中间件use一下,才能正确读取post发送过来的信息
router.post("/post",(ctx,next)=>{
console.log(ctx.request.body);
ctx.body = {
status:1,
info:"post请求成功"
}
})
前端页面配置
document.querySelector("button").onclick = function () {
let xhr = new XMLHttpRequest();
xhr.open("post", "/post", true);
xhr.onload = function () {
console.log(xhr.responseText);
// 获取返还头信息
// console.log(xhr.getAllResponseHeaders());
// console.log(xhr.getResponseHeader("content-type"));
}
// xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
// xhr.setRequestHeader("Content-Type","multipart/form-data"); //二进制编码
xhr.setRequestHeader("content-type","application/json");
// let data = "username=王五&age=20";
let data = JSON.stringify({
username:"王五",
age:20
})
xhr.send(data);
}
前端获取请求头的方法
-
getAllResponseHeaders
- 获取全部的头信息
-
getResponseHeader('name')
-
获取指定的name的头信息
-
console.log(xhr.getResponseHeader("content-type"));
-
ajax的同步、异步
异步就在同步任务进行中,ajax的请求没有影响。但是如果ajax 设置同步,那么要等同步的任务完成以后才能执行ajax的请求。我们官方推荐也是使用异步的。
xhr.open("get","/checkUser",true); //true是异步,false是同步
onreadystatechange
除了onload外还有检测服务器相应状态的函数onreadystatechange
onreadystatechange:存有处理服务器响应的函数,每当 readyState 改变时,onreadystatechange 函数就会被执行。
readyState:存有服务器响应的状态信息。
- 0: 请求未初始化(代理被创建,但尚未调用 open() 方法)
- 1: 服务器连接已建立(
open方法已经被调用) - 2: 请求已接收(
send方法已经被调用,并且头部和状态已经可获得) - 3: 请求处理中(下载中,
responseText属性已经包含部分数据) - 4: 请求已完成,且响应已就绪(下载操作已完成)
status常用状态码
| HTTP状态码 | 描述 |
| 100 | 继续。继续响应剩余部分,进行提交请求 |
| 200 | 成功 |
| 301 | 永久移动。请求资源永久移动到新位置 |
| 302 | 临时移动。请求资源零时移动到新位置 |
| 304 | 未修改。请求资源对比上次未被修改,响应中不包含资源内容 |
| 401 | 未授权,需要身份验证 |
| 403 | 禁止。请求被拒绝 |
| 404 | 未找到,服务器未找到需要资源 |
| 500 | 服务器内部错误。服务器遇到错误,无法完成请求 |
| 503 | 服务器不可用。临时服务过载,无法处理请求 |
document.querySelector("button").onclick = function () {
let xhr = new XMLHttpRequest();
xhr.open("get", "/get/4", true);
xhr.onload = function () {
console.log(xhr.responseText);
console.log(xhr.readyState);
console.log(xhr.status);
}
// xhr.onreadystatechange = function () {
// if (xhr.readyState == 4) {
// if (xhr.status == 200) {
// console.log(xhr.responseText);
// }
// }
// }
xhr.send();
}
xml数据返回
数据传输的除了json 还有xml ,xml要怎么返回。
页面
document.querySelector("button").onclick = function(){
let xhr = new XMLHttpRequest();
xhr.open("get","/xml",true);
// 如果后端没有设置 xml ,前端可以重写content-type;
xhr.overrideMimeType("text/xml");
xhr.onload = function(){
// console.log(xhr.responseText);
// console.log(xhr.responseXML);
// console.log(xhr.response)
let name = xhr.responseXML.getElementsByTagName("name")[1].innerHTML;
console.log(name);
}
xhr.send();
}
服务器
router.get("/xml",(ctx,next)=>{
// ctx.set("content-type","text/xml");
ctx.body = `<?xml version='1.0' encoding='utf-8' ?>
<books>
<nodejs>
<name>nodejs</name>
<price>6元</price>
</nodejs>
<react>
<name>react</name>
<price>5元</price>
</react>
</books>
`
})
formData文件上存
现在我们传输数据都是普通的文字数据,那么我们要上存文件,视频,图片等文件我们就需要使用formData。
特殊的file标签
需要使用type file的标签用于文件上存
<body>
<input type="file" class="myfile" />
<button>点击我上传文件</button>
</body>
post提交
上存文件要用post的方式。
简易的文件上存
-
前端
document.querySelector("button").onclick = function(){ let file = document.querySelector(".myfile").files[0]; // console.log(files); let form = new FormData(); form.append("img",file); // form.append("name","张三"); let xhr = new XMLHttpRequest(); xhr.open("post","/upload",true); xhr.onload = function(){ console.log(xhr.responseText); } xhr.send(form); } -
后台服务器处理
这里要注意,存过来的文件node帮我创建了一个临时路径,我们要利用fs模块变成实际的硬盘路径
router.post("/upload",(ctx,next)=>{ console.log(ctx.request.body); console.log(ctx.request.files.img); let fileData = fs.readFileSync(ctx.request.files.img.path); fs.writeFileSync("static/imgs/"+ctx.request.files.img.name,fileData); ctx.body = "请求成功"; })
监控上存速度,上存进度
创建formData对象后。onload事件有几个事件钩子
upload 事件里面的事件钩子
-
onloadstart 上传开始
-
onprogress 数据传输进行中
这个方法用来计算上存速度和上存进度,用到下面两个对象。
进度计算
- evt.total :需要传输的总大小;
- evt.loaded :当前上传的文件大小;
- 上存进度公式: (evt.loaded/evt.total*100).toFixed(0)
速度计算
- 思路:拿到一个时间段的时间差 -->Date.getTime()方法
- 思路:拿到一个时间段的上存文件的大小 -->evt.loaded 对象
- 最后就是文件大小除以时间差等于速度
-
onabort 上传操作终止
-
onerror 上传失败
-
onload 上传成功
-
onloadend 上传完成(不论成功与否都会执行)
<body>
<input type="file" class="myfile" />
进度:<progress value="0" max="100"></progress> <span class="percent">0%</span>
速度:<span class="speed">20b/s</span>
<button>点击上传</button>
<button>取消上传</button>
</body>
<script>
let xhr = new XMLHttpRequest();
let btns = document.querySelectorAll("button");
let stime;
let sloaded;
btns[0].onclick = function () {
let file = document.querySelector(".myfile").files[0];
let form = new FormData();
form.append("myfile", file);
xhr.open("post", "/fileUpload", true);
xhr.onload = function () {
console.log(xhr.responseText);
}
xhr.upload.onloadstart = function(){
console.log("开始上传");
stime = new Date().getTime();
sloaded = 0;
}
xhr.upload.onprogress = function(evt){
let endTime = new Date().getTime();
// 时间差;
let dTime = (endTime - stime)/1000;
// 当前时间内上传的文件大小
let dloaded = evt.loaded - sloaded;
let speed = dloaded/dTime;
let unit = "b/s";
stime = new Date().getTime();
sloaded = evt.loaded;
if(speed/1024>1){
unit = "kb/s";
speed = speed/1024;
}
if(speed/1024>1){
unit = "mb/s";
speed = speed/1024;
}
document.querySelector(".speed").innerHTML = speed.toFixed(2)+unit;
// console.log(speed.toFixed(2));
// console.log("正在上传");
// 当前文件上传的大小evt.loaded
// 需要上传文件的大小
let percent = (evt.loaded/evt.total*100).toFixed(0);
// console.log(percent);
document.querySelector("progress").value = percent;
document.querySelector(".percent").innerHTML = percent+"%";
}
xhr.upload.onload = function(){
console.log("上传成功");
}
xhr.upload.onloadend = function(){
console.log("上传完成");
}
xhr.upload.onabort = function(){
console.log("取消上传");
}
xhr.send(form);
}
btns[1].onclick = function(){
xhr.abort();
}
服务器
router.post("/fileUpload",(ctx,next)=>{
console.log(ctx.request.files);
let fileData = fs.readFileSync(ctx.request.files.myfile.path);
fs.writeFileSync("static/imgs/"+ctx.request.files.myfile.name,fileData);
ctx.body = "请求成功";
})