如何开发rest接口服务_如何简化网络请求接口开发
面對的問題
首先,明確下我們要解決什么問題,因為說到網絡請求調用,使用 axios 庫就可以了,上手簡單,提供請求攔截功能,大多數場景都可以覆蓋到,為什么要再去做額外的開發?
axios 做基礎的庫可以滿足日常開發需要,不過出于架構設計、復用和便于維護的需要,通常我們會進行分層,抽出一個數據訪問邏輯層,專門去處理和后端的接口訪問,這個層對上層提供清晰可讀性好的接口,便于對數據進行聚合裁剪。
在這個數據訪問邏輯層,通常會調用 axios 或者其他的庫進行接口的訪問,通常會有如下的場景,需要我們處理:
以上是我總結的一些需求,不知道大家有沒有類似的場景,針對這些需求,大家是如何滿足的呢?
實現目標
針對以上問題,我們希望通過簡單的配置即可滿足需要,簡化網絡請求實現,提高接口對接效率,將開發者的注意力集中在UI層的交互和業務邏輯開發。
具體如下:
實現
簡單可配置
示例:
全局配置:
import { buildApi, http } from 'biz-lib'; let count = 0; export default function (opts) {return buildApi(opts, {isDev:process.env.NODE_ENV === 'development', /*** 統一設置請求域名*/host:'http://exam.china.com',/*** 將請求定向到 mock 服務器*/ mock(url,option) {return http.get(`${mock.host}/mockjsdata/${mock.projectId}${url}`);},/*** 請求執行前*/before() {Loading.show('請稍后...');count++;},/*** 請求執行后*/after() {count--;if (count <= 0) {Loading.hide();count = 0;}},/** * 過濾器,對請求預處理,和后端閱讀 code 值,* code = 1 直接返回數據,其他可以拋異常,或自定義處理*/filters: [function (res) {if (res.code == 1) {return res.data;} else if (res.code === -1) {throw new CodeError(-1, res.msg);} else if (res.code === 100) {throw new CodeError(100, '您尚未登錄');}return res;},],// 統一處理異常,onError(err) {Loading.hide();count = 0;if (typeof err.code === 'undefined' || err.code === -1 ) {message.warning(err.message);} else if (err.code === 100) {window.location.href='/login'}throw err;},}); }單一接口配置示例:
import { buildApi } from './api'; const apis = buildApi({/*** POST 請求示例*/'submitAnswer': {url: '/cexam/api/answer/submit/{id}'method:'GET' | 'POST' | 'Jsonp',format:'form' | 'json' | 'form-data',cache: true | false,storage:'sessionStorage' | 'localStorage' | 'memoryStorage',merge: true | false,mock:function(url,data,option){},before:function(){},after:function(){},filters:[],headers:{},},/*** GET 請求示例*/'getQuestionList': '/cexam/api/exam/group/list/{id}' : });export const submitAnswer=(id:string,data:IParams)=>{// 調用post請求return apis.submitAnswer({id},{data}) }export const getQuestionList=(id:string)=>{// get請求apis.getQuestionList({id}) }接口邏輯層需要對調用方提供可讀的 API,可以利用 Typescript 對接口進行定義,調用方調用體驗會很好。
配置項說明:
- method 請求類型,包括:POST/GET
- format 請求數據格式,包括:json/form/form-data
- cache 緩存請求數據(不刷新瀏覽器的情況下)
- storage 可以將請求緩存到存儲,包括 sessionStorage/localStorage/memoryStorage
- merge 相同接口請求是否合并
- before 請求發起之前執行
- after 請求發起之后執行
- filters 函數式一個函數數組,前一個函數的輸出是后一個函數的輸入
- mock 提供請求的 mock 方法,自定義 mock。
- headers 自定義請求頭
- url 請求的 url,可以內嵌參數,比如 list/{id}
- 參數 通過大括號 {} 設置,通過方法的第一次參數指定,和 {} 中設定的同名即可
請求響應攔截
提供請求響應攔截功能,處理通用業務邏輯,比如: - 請求之前和請求之后顯示和隱藏全局 Loading - 請求返回后預處理返回數據,減少調用端代碼 - 統一處理例外情況,比如異常,登錄超時,賬號余額不足等等。
統一異常處理的前提是后端返回的規范的數據結構,比如{code:0,data:'',message:''},約定 code 值,code 等于多少是請求正常,多少是異常,以及其他例外情況。
- 網絡通信異常
- 程序執行異常
- 非異常的例外情況,比如登錄超時、考試已結束、余額不足等
可以針對不同的異常進行編碼,方便接口調用方捕獲異常后進行自定義處理,類似后端的自定義異常類型,但是后端可以根據類型進行捕獲,前端是弱類型,只好靠編碼來識別異常了。
示例如下:
let apis=buildApi({'submitAnswer': {method: 'POST',url: '/cexam/api/answer/submit'} }, {filters: [function (res) {if (res.code == 1) {// code = 1 直接返回數據return res.data;} else if (res.code == -1) {throw new CommonlError(-1, res.message);} else if (res.code == -2) {// 考試已結束處理 throw new ExamTerminalError(-2, '考試已結束');} else if (res.code == -3) {// 余額不足處理throw new CommonlError(-3, res.message);} else if (res.code == 10) {// 登錄超時處理return window.location.href = '/login';}return res;},function (res){return res;}],//統一處理異常,onError(err) {if (err['code'] == -1) {message.warning(err.message);}throw err;} });調用
try{let data = await apis.submitAnswer();await apis.operationA(data);await apis.operationB(); }catch(err){if(err.code==-2){//處理考試結束的例外情況}else if(err.code == -3){//處理余額不足} }經過請求預處理,正常情況下直接返回后端數據,不需要判斷 code 值,統一異常處理以后,通過 catch 捕獲異常,自定義處理邏輯。
整體的編程體驗很類似 Java 或者 C#。
請求合并
前文提到了需要請求合并的場景,比如有兩個獨立的組件,但是使用了相同的一個接口,即希望組件相互獨立沒有依賴,又希望相同請求只請求一次。
每個使用 buid-api 的地方都需要配置merge:true,可以共享一次請求。
const api1 = buildApis({'getProjectAuth':{method:'GET',merge:true,url:'/api/project/auth'} }); const api2 = buildApis({'getProjectAuth':{method:'GET',merge:true,url:'/api/project/auth'} }); //如果api1調用過,api2會復用api1的返回結果請求合并的實現比較取巧,如果判斷有相同的請求,只要第二個請求復用第一個請求返回的 Promise 即可,
請求緩存
針對需要多次訪問的請求,數據不變的話,可以設置緩存。
可以設置緩存的存儲,默認是 memoryStorage,用戶可以自定義 storage 的實現。
const api1 = buildApis({'getProjectAuth':{method:'GET',cache:true,storage:'sessionStorage' | 'localStorage' | 'memoryStorage',url:'/api/project/auth'} }); const api1 = buildApis({'getProjectAuth':{method:'GET',cache:true,storage:{get(key){},set(key,value){}},url:'/api/project/auth'} });MOCK 數據
可以提供統一的 mock配置,或者單獨配置,單獨配置的 mock 優先執行。
具體 mock 采用什么技術,由調用方決定,比如可以使用 json,或者 rap,或者 mockjs 庫等。
如果采用本地 node 代理,可以不用設置 mock;
const apis = buildApi({'submitAnswer': {method: 'POST/GET',format:'json/form/form-data',url: '/cexam/api/answer/submit',mock(url,data,option){return {id:1,name:'test'};}},'getQuestionList': '/cexam/api/exam/group/list/{id}' : },{mock(url,data,option) {return http.get(`${RAP.host}/mockjsdata/${RAP.projectId}${url}`);}, });安全檢查
統一提供安全檢查過濾,針對參數以及返回數據進行 xss 過濾,csrf token 添加,可以參考 axios 的方式。
最后
本文總結了常見的網絡接口對接開發過程中常見的問題,并且針對需求提供了一個簡單可配置的方案,極大的簡化網絡接口對接開發,提供了包括:請求響應攔截,合并,緩存,統一異常處理,Mock 等功能,簡化了接口的調用,提升開發效率。
碼字不易,覺得有收獲就隨手給個贊唄,謝謝^_^!
總結
以上是生活随笔為你收集整理的如何开发rest接口服务_如何简化网络请求接口开发的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: java cache详解,Java内存缓
- 下一篇: php 拖动多个文件上传,dropzon
