前后端交互基础ajax(一)

1,622 阅读5分钟

前后端交互基础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 = "请求成功";
})