基於阿裏的Node全棧之路(五)前後端分離進階-接口篇
上一篇文章我就簡單的貼了下代碼,放出來不到一天就破千了,這讓我非常的意外,也很開心;) 我會好好的把上一篇的代碼注釋補一下的。然後決定再放一些我的代碼和理解,俗話說:
Talk is cheap, show me the code!
還記得我的架構中,隻有前端靜態代碼,同時所有的請求是經過跨域發到api上的,那麼這次,我們就來好好的分析下request接口的實現和我自己嚐試的一種的開發流程——api文檔(新接口文檔)
先貼上我之前的前後端分離的方式,再簡單的介紹下,看過前麵文章的同學直接跳過哈!
看這個圖,我現在對web端的開發,因為是用vue寫的,vue本身會把代碼打包成靜態文件:
- -static
- -index.html
這樣意味著,用了vue或者類似框架的時候,我們會拋棄了以前的一個東西叫動態web語言,具體點就是說像asp、jsp等,在客戶訪問前會根據一些條件渲染出對應的網頁出來,而這正是vue這類型的框架要實現的功能,嗯,可以說是衝突了。我當時還會習慣性的部署docker容器來存放這些靜態資源,然後啟動一個node express來監聽接口,但後來仔細想想,這不是像OSS這些要做的事情嗎!? 所以,就有了前麵的兩篇文章:
1. 基於阿裏的Node全棧之路(三)利用阿裏雲OSS實現前後端分離
編輯 刪除
2. 基於阿裏的Node全棧之路(四)前後端分離進階-自動上傳前端代碼到OSS
嗯嗯,這也是我前後端分離的第一步。
好,上麵都是重新溫故下我之前的文章,因為我發現看我前麵幾篇文章好像並沒有想象中的那麼容易閱讀,所以再次重溫一遍。
敲黑板!敲黑板!
這次,我分享的是我對api請求接口的封裝,可能很多同學會說,這有什麼難的,要用請求的時候,調用一下ajax什麼的就可以了。emmm..., 是可以的,不過那樣的代碼對於非常追求代碼美感的我來說,是灰常難忍受的!
既然我們是前後端分離,那麼我們應該規對接的接口的結構,對吧?我在項目中,強製規定所有的api都應該長這樣
const api_host = `https://api.${你的域名}\${你的項目名\${api_version}`;//https://api.xxxxx.com/blog/v1
//api遵循restful設計,這裏規定api返回結構
const response = {
code:Number,
/*
* 小於0是錯誤,這裏前端不需要關心錯誤是什麼,
* 等於0是沒有權限
* 大於0表示成功
* 我這麼設計是由原因的,歡迎大家來一起探討
*/
msg:String,//當然,你也可以叫errMsg,message什麼的,隨便你啦
/*
* 在我這裏,默認隻有錯誤的時候,才會出現
*/
data:Object,
/*
* 後端返回對象,我們一直說前後端語言一樣,有很多好處,呐,這裏就是!
* 這樣寫,基本能保證後端傳給前端是什麼,前端收到的就是什麼
*/
};
下麵放上我的代碼,然後我再詳細解析下:
/* eslint-disable */
import axios from 'axios';
const MyPlugin = {};
axios.defaults.withCredentials = true;//唯有加上這句話,才能夠支持跨域請求,如果實在不明白的可以留言
MyPlugin.install = function install(Vue, api_host) {
//構建axios請求基礎
const request = axios.create({
baseURL: api_host,//api host:顧名思義就是api的請求基礎地質
timeout: 30000// 超時時間
});
//請求方法的構建,type為:get、post、delete等等
const createRequestFuc = (type) => {
return function (resource, params, showError = true) {
//返回請求的Promise的對象
return new Promise((resolve, reject) => {
this.$Loading.start();//請求發起時,show loading,一般的框架都會有全局調用的loading方法。
params = type === 'get' ? { params } : params;//axios裏get方法和其它方法接收參數的方式不一致,這裏做個統一
request[type](resource, params)//調用request
.then(res => {
if (res && res.data && res.data.code > 0) {//判斷請求返回結果,code為判斷值,這裏可以替換成你自己的框架定義
resolve(res.data.data);//返回結果
} else {
showError && this.$Message.error(res.data.msg);//判斷是否調用自帶全局waring或error
reject(res.data.msg);//無論上麵是否執行,都應該reject,阻止代碼繼續執行
}
this.$Loading.finish();//結束loading
})
.catch((err) => {
this.$Message.error('請求失敗!');//這種情況一般是請求失敗,報錯方式可以自己更改
this.$Loading.finish();//結束loading
reject(err);//無論上麵是否執行,都應該reject,阻止代碼繼續執行
});
//特別注意:vue install方式安裝的插件,this就是vue component對象。
});
}
}
//構建請求
Vue.prototype.$get = createRequestFuc('get');
Vue.prototype.$put = createRequestFuc('put');
Vue.prototype.$post = createRequestFuc('post');
Vue.prototype.$patch = createRequestFuc('patch');
Vue.prototype.$delete = createRequestFuc('delete');
};
export default MyPlugin;
/* eslint-enable */
這是一個我寫的插件,上篇文章講到vuexiang項目用webpack模板構建對吧,那麼你現在寫前端xia項目應該都是以".vue"結尾的文件,那麼你隻需要在main.js裏麵把它引用進來就可以了:
import Vue from 'vue';
import Request from '@/plugins/request';
Vue.use(Vuex);
Vue.use(Request,'https://api.xxxxx.com/v1');//這裏
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
store,
template: '<App/>',
components: { App },
});
/* eslint-enable no-new */
好,到這裏估計寫過vue的老鳥都已經明白了,沒搞懂的童鞋嘞,那就繼續看下去吧!
接下來,你隻需要在vue文件裏麵直接使用就行了,這裏再貼一份簡單登錄代碼給大家參考:
<template>
<div >
<Input type="text" v-model="user_form.username" placeholder="phone">
<Input type="password" v-model="user_form.password" placeholder="phone">
<Button type="primary" @click="login">Log in</Button>
</div>
</template>
<script>
export default {
async created() {
const session = await this.$get('session', {}, false);
this.setSession(session);
},
data() {
return {
user_form: {
phone: '',
password: '',
},
};
},
methods: {
async login() {
const session = await this.$post('session', this.user_form);
this.setSession(session);
},
setSession(session) {
//這裏放置像vuex這些,存放session的fangfa,當然!你也可以用vuex的mapMutations,我就是這麼做的^.^
},
},
};
</script>
嘿嘿,上麵的代碼簡單不。當然,你要喜歡promise回調或者yield都一樣的,隨便你,我這裏隻是想分享一種思想,因為這種方式,是可以在node裏麵得到廣泛應用的,為了證明這點,我再貼一份我的react-native版本的request接口:
/* eslint-disable */
import axios from 'axios';
import { ShowWarnMsg } from './toast';
const api_host = 'https://api.xxxxxx.com/project_name/v1';
//構建axios請求基礎
const request = axios.create({
baseURL: api_host,//api host:顧名思義就是api的請求基礎地質
timeout: 30000// 超時時間
});
//請求方法的構建,type為:get、post、delete等等
const createRequestFuc = (type) => {
return function (resource, params, showError = true) {
//返回請求的Promise的對象
return new Promise((resolve, reject) => {
params = type === 'get' ? { params } : params;//axios裏get方法和其它方法接收參數的方式不一致,這裏做個統一
request[type](resource, params)//調用request
.then(res => {
if (res && res.data && res.data.code > 0) {//判斷請求返回結果,code為判斷值,這裏可以替換成你自己的框架定義
resolve(res.data.data);//返回結果
} else {
showError && ShowWarnMsg(res.data.msg);//判斷是否調用自帶全局waring或error
reject(res.data.msg);//無論上麵是否執行,都應該reject,阻止代碼繼續執行
}
})
.catch((err) => {
ShowWarnMsg('請求失敗!');//這種情況一般是請求失敗,報錯方式可以自己更改
reject(err);//無論上麵是否執行,都應該reject,阻止代碼繼續執行
});
//特別注意:vue install方式安裝的插件,this就是vue component對象。
});
}
};
export const $get = createRequestFuc('get');
export const $put = createRequestFuc('put');
export const $post = createRequestFuc('post');
export const $patch = createRequestFuc('patch');
export const $delete = createRequestFuc('');
global.HTTP = {
$get,
$put,
$post,
$patch,
$delete,
};
export default global.HTTP;
/* eslint-enable */
區別不大吧,別學我用global,我隻是偷懶。
最後更新:2017-09-27 14:04:21