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. 基於接口的案例

基於接口的圖書管理功能


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM