zoukankan      html  css  js  c++  java
  • Vue前后端交互模式

    • 前后端交互模式
    • promise用法
    • 接口调用-fetch用法
    • 接口调用-axios用法
    • 接口调用-async/await用法
    • 基于接口的案例

    1. 前后端交互模式

    ① 接口调用方式

    • 原生Ajax
    • 基于jQuery的Ajax
    • fetch
    • axios

    jQuery中的Ajax侧重点是DOM操作,而vue开发很少涉及到DOM操作,所以使用fetch和axios调用接口。

    ② URL地址格式

    1)传统形式的URL: 

    schema://host:port/path?query#fragment
    • schema:协议。例如http、https、ftp等
    • host:域名或者IP地址
    • port:端口,http默认端口是80,可以省略
    • path:路径,例如/abc/a/b/c
    • query:查询参数,例如uname=lisi&age=12
    • fragment:锚点(哈希hash),用于定位页面的某个位置

    例如下面都是符合规则的URL格式:

    • http://www.test.com
    • http://www.test.com/java/web
    • http://www.test.com/java/web?flag=1
    • http://www.test.com/java/web?flag=1#function

    2)Restful形式的URL

    HTTP请求方式:

    • GET:查询
    • POST:添加
    • PUT:修改
    • DELETE:删除

    例如下面都是符合规则的URL地址:

    • GET:http://www.hello.com/books   
    • POST:http://www.hello.com/books   
    • PUT:http://www.hello.com/books/123
    • DELETE:http://www.hello.com/books/123   

    2. promise用法

    ① 异步调用

    • 异步效果分析:
      • 定时任务
      • Ajax
      • 事件函数
    • 多次异步调用的依赖分析:
      • 多次异步调用的结果顺序不确定
      • 异步调用结果如果存在依赖,则需要嵌套
    // 多层嵌套会陷入回调地狱
    $.ajax({ success:
    function(data) { if (data. status == 200) { $.ajax ({ success: function (data) { if (data. status == 200) { $.ajax({ success: function(data) { if (data. status == 200) {} } }); } }); } } });

    ② Promise概述

    Promise是异步编程的一种解决方案,从语法上讲,Promise是一个对象,从它可以获取异步操作的消息

    使用Promise主要有以下好处:

    • 可以避免多层异步调用嵌套问题(回调地狱)
    • Promise对象提供了简洁的API,使得控制异步操作更加容易

    ③ Promise基本用法

    • 实例化Promise对象,构造函数中传递函数,该函数中用于处理异步任务
    • resolvereject两个参数用于处理成功失败两种情况,并通过p.then获取处理结果

    实际上就是把之前用到的回调函数用then的方式给重构了,这样的话代码就不会有多层嵌套了,而是变成线性结构。

    var p = new Promise (function (resolve, reject) {
        //成功时调用resolve ()
        //失败时调用reject ()
    });
    p.then( funciton (ret) {
        //从resolve得到正常结果
    },function(ret) { 
        //从reject得到错误信息
    });

    例如下面这段测试代码:

    var p = new Promise(function (resolve, reject) {
        //这里用于实现异步任务
        setTimeout(function() {
            var flag = false;
            if (flag) {
                // 正常情况
                resolve('hello');
            }else {
                // 异常情况
                reject('出错了');
            }
        }, 100);
    });
    p.then( funciton (data) {
        //从resolve得到正常结果
        console.log(data);
    },function(info) { 
        //从reject得到错误信息
        console.log(info);
    });

    ④ 基于Promise处理Ajax请求

    1)处理原生Ajax

    function queryData(url) {
        return new Promise (function(resolve, reject) {
            var xhr = new XMLHttpRequest () ;
            xhr.onreadystatechange = function() {
                if (xhr.readyState != 4) return; 
                if (xhr.readyState == 4 && xhr.status == 200) {
                    // 处理正常的情况
                    resolve(xhr.responseText);
                }else{
                    // 处理异常情况
                    reject('出错了');
                }
            }
            xhr.open('get', url);
            xhr.send(null);
        });
    }
    queryData('http://localhost:3000/data') 
        .then(function(data){
            console.log(data);
        },function(info){
            console.log(info);
        });

    2)发送多次Ajax请求

    // 发送多个Ajax请求并且要保证顺序
    queryData('http://localhost:3000/data') 
        .then(function(data){
            console.log(data);
            return queryData('http://localhost:3000/data1');
        })
        // 这个then是上面return的queryData的结果调用的
        .then(function(data){
            console.log(data);
            return queryData('http://localhost:3000/data2');
        })
        .then(function(data){
            console.log(data);
        });

    注意:return的是一个新的promise实例对象,下一个then调用者就是上面return出来的promise对象,并且then当中的函数的参数data用于接收上一个异步任务的处理结果。

    ⑤ Promise常用的API

    1)实例方法

    • p.then()得到异步任务的正确结果
    • p.catch()获取异常信息
    • p.finally()成功与否都会执行(尚且不是正式标准)

    例如下面这段测试代码:

    function queryData() {
        return new Promise(function(resolve, reject){
            setTimeout(function(){
                // resolve(123);
                reject(' error');
            }, 100);
        })
    }
    foo()
        .then(function(data){
            console.log(data)
        })
        .catch(function(data){
            console.log(data)
        })
        .finally(function(){
            console.log('finished')
        });

    可以把两个函数都传递给then,也可以then接受一个函数,另外一个通过catch来处理。catch的作用就是专门用来处理异常信息的。

    2)对象方法

    all和race都是对象方法,prototype里面的都是实例方法。

    • Promise.all() 并发处理多个异步任务,所有任务都执行完成才能得到结果
    • Promise.race() 并发处理多个异步任务,只要有一个任务完成就能得到结果
    var p1 = queryData('http://localhost:3000/a1');
    var p2 = queryData('http://localhost:3000/a2');
    var p3 = queryData('http://localhost:3000/a3');
    Promise.all([p1,p2,p3]).then(function(result){
        console.log(result)
    })
    Promise.race([p1,p2,p3]).then(function(result){
        console.log(result)
    })

    all()方法输出的是一个数组,数组中数据的顺序与promise实例对象的顺序是一一对应的。all()方法可以用于发送多个请求的,并且请求之间没有嵌套关系。

    race()方法得到的是最开始返回的一个结果,另外两个结果也已经返回回来了,但是我们并不关心。

    3. 接口调用-fetch用法

    ① fetch概述

    1)基本特性

    • 更加简单的数据获取方式,功能更强大、更灵活,可以看作是xhr的升级版
    • 基于Promise实现

    2)语法结构

    fetch(url).then(fn2)
              .then(fn3)
              ...
              .catch(fn)

    官网:https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API

    ② fetch的基本用法

    fetch('http://localhost:3000/fdata').then(data => {
        // text()方法属于fetchAPI的一部分,它返回一个Promise实例对象,用于获取后台返回的数据
        return data.text();
    }).then(function(data){
        // 注意这里得到的才是最终的数据
        console.log(data);
    });

    注意:这里面的data不能直接拿到实际的数据,而是要通过fetch中API:data.text()来获得数据,但是text()返回的是一个promise实例对象,所以需要把它return出去,然后通过下一个then来得到最终的数据。

    ③ fetch请求参数

    1)常用配置选项

    • method(String):HTTP请求方法,默认为GET(GET、POST、PUT、DELETE)
    • body(String):HTTP的请求参数
    • headers(Object):HTTP的请求头,默认为{}
    fetch('/abc', {
      method: 'get'  
    }).then(data => {
       return data.text(); 
    }).then(ret => {
       // 注意这里得到的才是最终的数据
       console.log(ret);  
    });

    2)GET请求方式的参数传递

    fetch('/abc?id=123', {
        method: 'get'
    }).then(data=>{
        return data.text();
    }).then(ret => {
        //注意这里得到的才是最终的数据
        console.log(ret);
    });

    Restful风格的API:

    fetch('/abc/456'), {
        method: 'get'
    }).then(data => {
        return data.text();
    }).then(ret => {
        //注意这里得到的才是最终的数据
        console.log(ret);
    });

    后台接口:

    app.get('/abc', (req, res) => {
        res.send('传统的URL传递参数!' + req.query.id);
    });
    app.get('/abc/:id', (req, res) => {
        res.send('Restful形式的URL传递参数!' + req.params.id);
    });

    3)DELETE请求方式的参数传递

    fetch('/abc/123', {
        method: 'delete'
    }).then(data => {
        return data.text();
    }).then(ret => {
        //注意这里得到的才是最终的数据
        console.log(ret);
    });
    app.delete('/abc/:id', (req, res) => {
        res.send('DELETE请求传递参数!' + req.params.id);
    });

    4)POST请求方式的参数传递

    • 传递拼接字符串格式的数据:
    fetch('/books', {
        method: 'post',
        body: 'uname=lisi&pwd=123',
        headers: {
            'Content-Type': 'application/x-www-form-urlencoded'
        }
    }).then(data => {
        return data.text();
    }).then(ret => {
        console.log(ret);
    });

    请求头是必须要设置的,否则内容传递不过去。

    后台必须要使用第三方模块body-parser来接收post发送过来的数据

    // 处理post请求中的json格式的数据
    app.use(bodyParser.json());
    // 处理post请求中的字符串格式的数据
    app.use(bodyParser.urlencoded({extended: false}));
    app.post('/books', (req, res) => {
        res.send('POST请求传递参数!' + req.body.umane + '---' + req.body.pwd);
    })
    • 传递json格式的数据:
    fetch('/books', {
        method: 'post',
        body: JSON.stringify({
            uname: 'lisi',
            age: 12
        }),
        headers: {
            'Content-Type': 'application/json'
        }
    }).then(data => {
        return data.text();
    }).then(ret => {
        console.log(ret);
    });

    后台接口还是和上面一样,没有变化。

    5)PUT请求方式的参数传递

    fetch('/books/123', {
        method: 'put',
        body: JSON.stringify({
            uname: 'lisi',
            age: 12
        }),
        headers: {
            'Content-Type': 'application/json'
        }
    }).then(data => {
        return data.text();
    }).then(ret => {
        console.log(ret);
    });
    app.put('/books/:id', (req, res) => {
        res.send('PUT请求传递参数!' + req.params.id+ '---' + req.body.uname + '---' + req.body.pwd);
    })

    ④ fetch响应结果

    响应数据格式:

    • text():将返回体处理成字符串类型
    • json():返回结果和JSON.parse(responseText)一样

    后台返回json格式的数据:

    app.get('/json', (req, res) => {
        res.json({
            uname: 'lisi',
            age: 13,
            gender: 'male'
        });
    });

    客户端接收到后台传递过来的数据:

    fetch('/json').then(data => {
        // json()方法返回的就是json格式的数据
        return data.json();
    }).then(ret => {
        //注意这里得到的才是最终的数据
        console.log(ret);
    });
    
    // 类似于下面这步:
    fetch('/json').then(data => {
        return data.text();
    }).then(ret => {
        //还需要自己将数据转换为json格式
        var obj = JSON.parse(data);
        console.log(obj.uname, obj.age, obj.gender);
    });

    4. 接口调用-axios用法

    ① axios的基本特性

    axios是一个基于Promise用于浏览器和node.js的HTTP客户端。

    官网:https://github.com/axios/axios

    它具有以下特征:

    • 支持浏览器和node.js
    • 支持Promise
    • 能拦截请求和相应
    • 自动转换JSON数据

    axios是一个专门的第三方的JS库,用来实现接口的调用。

    ② axios的基本用法

    axios.get('/adata')
         .then(ret => {
             // data属性名称是固定的,用于获取后台响应的数据
             console.log(ret.data);
         })

    注意:ret是形参,并不是我们实际需要得数据,而是要通过ret.data才能获得我们最终想要的数据,其中data的名字是固定的

    ③ axios常用的API

    • get:查询数据
    • post:添加数据
    • put:修改数据
    • delete:删除数据

    ④ axios的参数传递

    1)GET传递参数

    • 通过URL传递参数
    • 通过params选项传递参数

    方法一:

    axios.get('/adata?id=123')
         .then(ret => {
             console.log(ret.data);
         })

    方法二:

    axios.get('/adata/123')
         .then(ret => {
             console.log(ret.data);
         })

    方法三:

    axios.get('/adata', {
        params: {
            id: 123
        }
    })
    .then(ret => {
        console.log(ret.data);
    })

    后台接收数据:

    app.get('/adata', (req, res) => {
       res.send('axios get 传递参数' + req.query.id); 
    });
    app.get('/axios/:id', (req, res) => {
       res.send('axios get (Restful)传递参数' + req.params.id); 
    });

    注意:前端如果是用params传参(例如方法三),则后台接口调用的还是req.query,而不是req.params

    2)DELETE传递参数

    • 参数传递方式与GET类似

    方法一:

    axios.delete('/adata?id=123')
         .then(ret => {
             console.log(ret.data);
         })

    方法二:

    axios.delete('/adata/123')
         .then(ret => {
             console.log(ret.data);
         })

    方法三:

    axios.delete('/adata', {
        params: {
            id: 123
        }
    })
    .then(ret => {
        console.log(ret.data);
    })

    3)POST传递参数

    post请求的两种传参方式:

    • 通过选项传递参数(默认传递的是json格式的数据
    axios.post('/adata', {
        uname: 'tom',
        pwd: 123
    }).then(ret => {
        console.log(ret.data);
    })    
    • 通过URLSearchParams传递参数(application/x-www-form-urlencoded)
    const params = new URLSearchParams();
    params.append('uname', 'zhangsan');
    params.append('pwd', '123');
    axios.post('/adata', params).then(ret => {
       console.log(ret.data); 
    })

    两种方式的后台接口都一样:

    app.post('/adata', (req, res) => {
       res.send('axios post 传递参数' + req.body.uname + '---' + req.body.pwd); 
    })

    4)PUT传递参数

    • 参数传递方式与POST类似
    axios.put('/adata/123', {
        uname: 'tom',
        pwd: 123
    }).then(ret => {
        console.log(ret.data);
    })  
    app.put('/adata/:id', (req, res) => {
       res.send('axios put 传递参数' + req.params.id + req.body.uname + '---' + req.body.pwd); 
    })

    ⑤ axios的响应结果

    响应结果的主要属性:

    • data:实际响应回来的数据
    • headers:响应头信息
    • status:响应状态码
    • statusText:响应状态信息
    axios.post('/axios-json').then(ret => {
       console.log(ret); 
    })

    axios中对于json响应数据来说,返回来的数据不需要我们自己再做转化了,axios内部已经处理好了,直接可以当对象来使用。例如:ret.data.username

    ⑥ axios的全局配置

    axios.defaults.timeout = 3000;  // 超时时间
    axios.defaults.baseURL = 'http://localhost:3000/app';  // 默认地址
    axios.defaults.headers['mytoken'] = 'aqwerwqwer2ewrwe23eresdf23'  // 设置请求头

    在设置完基准路径的时候,在实际调用接口的时候就可以简化操作,请求发出去的时候实际上会自动拼接上基准路径。

    对于跨域来说,请求头是需要后台来进行配置的:

    // 允许请求头为mytoken的传递
    res.header('Access-Control-Allow-Headers', 'mytoken');

    ⑦ axios拦截器

    1)请求拦截器:在请求发出之前设置一些信息。

    // 添加一个请求拦截器
    axios.interceptors.request.use (function(config) { 
        console.log(config.url);
        config.headers.mytoken = 'nihao';
        //在请求发出之前进行些信息设置
        return config;
    }, function (err) {
        //处理响应的错误信息
        console.log(err);
    });

    注意:一定要把config return出去,否则是不生效的。

    通过上面的拦截器可以控制所有的请求,这样就给每个请求设置了一个响应头:

    axios.get('http://localhost:3000/adata').then(data => {
       console.log(data); 
    });

    上面的axios请求就有一个mytoken的请求头:

    2)响应拦截器:在获取数据之前对数据做一些加工处理

    // 添加一个响应拦截器
    axios.interceptors.response.use (function(res) { 
        console.log(res);
        var data = res.data;
        //在这里对返回的数据进行处理
        return data;
    }, function (err) {
        //处理响应的错误信息
        console.log(err);
    });

    注意:形参res也不是我们需要的实际数据,而是axios所包装的对象,通过对象中的data才能拿到实际的数据。

    上面的响应拦截器中已经对res做了处理,所以返回的是我们实际需要的数据,所以在每个请求中不用再使用res.data来获取实际需要的数据:

    axios.get('http://localhost:3000/adata').then(data => {
       // 这个data不是axios对象,而是我们实际需要的数据 
       console.log(data); 
    });

    返回的不再是数据对象了,而是我们需要的数据。这样以后我们调用任何接口,所有的then当中得到的数据都是我们实际需要的后台返回来的数据,不需要再通过.data的方式来获取数据了。

    5. 接口调用-async/await用法

    虽然promise调用接口的方式相比于传统的回调函数的方式还是方便很多,但promise也不是最好的办法,比如说我们要发送多个异步接口的调用,要想保证它们的顺序,得通过then的方式来进行链式的操作,这样从代码的层面还是不够简洁的。为了进一步的提高编程体验,就诞生了一种新的语法async/await: 

    ① async/await的基本用法

    • async/await是ES7引入的新语法,可以更加方便地进行异步操作
    • async关键字用于函数上(async函数地返回值是Promise实例对象)
    • await关键字用于async函数当中(await可以得到异步的结果)
    async function queryData(id) {
        const ret = await axios.get('/data');
        return ret;
    }
    queryData.then(ret => {
        console.log(ret);
    });

    注意:

    • get请求参数返回来的是一个promise实例对象,在这个实例对象前面接上一个await,这样就可以直接通过返回值来得到异步的结果了。不再需要then,也不再需要回调函数了。
    • 这种函数的返回值也是一个promise实例对象,如果在async函数的内部直接把得到的异步结果再返回出去,那么这个函数在被调用的时候就可以通过then的方式来得到上面的返回值。
    • await后面必须跟一个promise实例对象。
    var ret = await new Promise(function(resolve, reject){/*...*/});

    ② async/await处理多个异步请求

    // 设置默认的基准地址
    axios.defaults.baseURL = 'http://localhost:3000'; 
    async function queryData() {
        var info = await axios.get('async1');
        var ret = await axios.get('async2?info=' + info.data);
        return ret.data;
    }
    queryData().then(function(data){
        console.log(data);
    });
    app.get('/async1', (req, res) => {
       res.send('hello'); 
    });
    app.get('/async2', (req, res) => {
       if(req.query.info == 'hello'){
            res.send('world');
       }else {
            res.send('error');
        }
    });

    await这种异步处理方式相当于之前的普通函数的调用,可以直接拿到结果,而不用担心多个异步任务的执行顺序问题。

    6. 基于接口的案例

    基于接口的图书管理功能

  • 相关阅读:
    安装lnmp 时如何修改数据库数据存储地址及默认访问地址
    ubuntu 设置root用户密码并实现root用户登录
    解决ubuntu 远程连接问题
    linux 搭建FTP服务器
    PHP 根据ip获取对应的实际地址
    如何发布自己的composer包
    使用composer安装composer包报Your requirements could not be resolved to an installable set of packages
    laravel 框架配置404等异常页面
    使用Xshell登录linux服务器报WARNING! The remote SSH server rejected X11 forwarding request
    IoTSharp 已支持国产松果时序数据库PinusDB
  • 原文地址:https://www.cnblogs.com/zcy9838/p/13156522.html
Copyright © 2011-2022 走看看