<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                # 跨平臺Axios服務封裝,支持后端多種微服務對接 ## 前言 大家封裝axios是否都是通過攔截服務呢?處理時,大多從以下問題出發吧,具體代碼可[點擊](http://www.hmoore.net/vvmily_king/vvmily/2326097)前往。 1、統一處理請求頭headers信息,如口令(token、Authorization)信息 2、重復接口防止提交,如采用loading、防抖處理等 3、請求入參統一,post、put、facth和get等方式 4、對響應數據狀態處理,如登錄攔截 5、對響應數據信息(錯誤)處理 6、其他:對文件請求處理... * 實現方式 ``` // 添加請求攔截器 axios.interceptors.request.use(function(config){ // ... 在發送請求前,統一做點什么,如請求頭配置、token信息等處理 return config; },function(error){ // ... 對請求錯誤統一做點什么 return Promise.reject(error) }) // 添加響應攔截器 axios.interceptors.response(function(response){ // ... 對響應數據做點什么 return response; },function(error){ // ... 對錯誤數據統一做點什么 return Promise.reject(error) }) export default axios; ``` ## 進入本文主題,如何實現跨平臺接口封裝,支持后端多種微服務對對接 封裝Api服務,解決以下問題 1、支持跨平臺,可直接復用于多平臺,如移動端、PC端、小程序; 2、支持多服務,后端基本不會只有一個服務,一般大點公司,都是 網關+N服務方式(核心); 3、集中配置、解耦、可移植,簡化開發流程,開發體驗也是杠杠的。 ## 結構目錄 services apis ---接口配置列表 base ---單一工具 axiosAjax.js ---ajax封裝 jsonpAjax.js ---jsonp封裝 config.js ---基本配置 couplingAjax.js ---ajax數據統一處理 index.js ---導出出口 ![](https://img.kancloud.cn/b2/70/b2706bac803d081e1c9b7b74b0cea645_435x323.png) ## 代碼使用 * apis/BaseServer/index.js文件 ``` export?default?function?BaseServer(ajax,?config)?{ ??return?{ ????//?根據城市名稱模糊搜索 ????queryList:?opt?=> ??????ajax({ ????????url:?"/sale/list", ????????method:?"get", ????????...opt ??????}) ??}; } ``` * 在業務組件中引入`import Api from "./services";`,得到的一定是正確的數據 ``` // 前提 import Api from "./services"; const opt = { ??????data:?{ ????????// ... ????????pageNum:?1, ????????pageSize:?15 ??????}, ??????loading:?true ??????//?success:?true } Api.BaseServer.queryList(opt).then(res?=>?{ ??????console.log("拿到一定是正確的數據",?res); ????}); ``` *Ajax請求配置以及請求后數據統一處理配置,如上`queryList(opt)`方法傳入opt對象配置如下: 注:下邊的配置項,適當的把部分配置放`apis/BaseServer/index.js文件`配置,部分存放到業務組件中。 | 配置項 | 說明 | ?是否必填 | 類型 | 默認值 | | --- | --- | --- | --- | --- | |?url?|?請求Api?|?是?|?string?|? ?| |?loading?|?加載攔截,全屏?|?否?|?boolean?|?false?| |?baseURL?|?基礎路徑?|?否?|?string?|??| |?data?|?請求發送數據?|?否?|?object?|??| |?params?|?地址欄拼接數據,僅限于'put',?'post',?'patch'?|?否?|?object?|??| |?timeout?|?超時時間?|?否?|?number?|?30?*?1000?| |?method?|?請求方法:get、post、put、patch、jsonp??|?否?|?string?|?get?| |?headers?|?請求頭?|?否?|?object?|?{?"Content-Type":?"application/json"?}?| |?success?|?請求成功時,是否提示?|?否?|?boolean?|?false?| |?error?|?請求失敗時,是否提示?|?否?|?boolean?|?true?| |?jsonp?|?是否使用jsonp請求接口?|?否?|?boolean?|?false?| |?jsonpOpt?|?jsonp庫的options參數,配合jsonp使用?|?否?|?object?|?false?| |?file?|?是否為文件模式?|?否?|?boolean?|?false?| |?mock?|?是否為mock模式?|?否?|?boolean?|?false?|? |?responseType?|?數據格式?|?否?|?string?|?json?| |?isResponse?|?是否簡化數據?|?否?|?boolean?|?false?|? |?reLogin?|?是否校驗登錄?|?否?|?boolean?|?true?| ## 代碼開發 * 基本配置 ``` //?接口和頁面初始化配置中心 //?在前置配置之前,需要搞清楚后端微服務前綴路由是什么,然后再配置到該文件下面 const?gateway?=?""; let?service?=?{ ??domainName:?"",?//?主域名 ??gateway,?//?流量網關前綴,后面的才是微服務后端代碼前綴 ??BaseServer:?gateway?+?"/order"?//?公共服務 }; console.log("當前環境",?process.env.VUE_APP_NODE_ENV); switch?(process.env.VUE_APP_NODE_ENV)?{ ??//?當走淘寶mock的情況 ??case?"rapmock":?{ ????service?=?{ ??????...service ????}; ????break; ??} ??//?開發,?本地開發走vue代理 ??case?"development":?{ ????service?=?{ ??????...service, ??????domainName:?"" ????}; ????break; ??} ??//?測試環境 ??case?"staging":?{ ????service?=?{ ??????...service, ??????domainName:?"" ????}; ????break; ??} ??//?生產 ??case?"production":?{ ????service?=?{ ??????...service, ??????domainName:?"" ????}; ????break; ??} } export?default?service; ``` * services/index.js ``` import?{?BaseApi?}?from?"./couplingAjax"; import?config?from?"./config"; import?BaseServer?from?"./apis/BaseServer"; const?baseServer?=?opt?=>?BaseApi(opt,?{?prefix:?config.BaseServer?}); export?default?{ ??BaseServer:?BaseServer(baseServer,?config) }; ``` * couplingAjax.js文件 請求頭信息、登錄校驗、響應數據都可在本文件中自行配置 ``` import { ajax } from "./base/axiosAjax"; import config from "./config"; import Tips from "./base/tips"; // import { loginOut } from '@/services/tool/LoginSet' // import vuex from "@/store/index"; import qs from "qs"; import { debounce } from "@/utils/antiShakingAndThrottling"; // 口令封裝處理 const handlerToken = (header = {}) => { const token = "token-test"; // vuex.getters.token; if (!token) return header; header["Authorization"] = token; return header; }; // 401退出登錄 const signOut = debounce(() => { // loginOut() Tips.error({ msg: "用戶登錄失效,將重新登錄", title: "錯誤" }); }, 1000); // 處理opt傳入參數 const handlerData = (opt, apiBase = {}) => { const { prefix } = apiBase; opt.baseURL = opt.baseURL ? opt.baseURL : config.domainName; opt.url = prefix + opt.url; opt.method = opt.method ?? "get"; opt.data = opt.data ?? {}; opt.headers = opt.headers ?? { "Content-Type": "application/json" }; // 設置默認headers opt.headers = handlerToken(opt.headers); opt.file = opt.file ?? false; // 是否為文件模式,文件下載模式為后端直接下載文件,不做處理判斷 opt.mock = opt.mock ?? process.env.VUE_APP_NODE_ENV === "rapmock"; // 是否為mock模式 // opt.responseType = opt.responseType ?? (opt.mock ? 'json' : 'text') // 細節需要加括號,上環境情況下后端返回的數據是base64字符串 opt.responseType = opt.responseType ?? "json"; opt.isResponse = opt.isResponse ?? false; // 是否直接獲取response數據,避免因為簡化data數據獲取導致無法獲取完整數據情況 opt.reLogin = opt.reLogin ?? true; // 是否判斷401狀態跳轉到登錄頁面 return opt; }; // 錯誤信息 const handlerErrorMessage = (error, message, tipsCode) => { error && Tips.error({ msg: error !== true ? error : message ?? "系統異常,請稍后重試!", tipsCode }); }; // 成功信息 const handlerSuccessMessage = (success, message, tipsCode = "") => { success && Tips.success({ msg: success !== true ? success : message ?? "成功", tipsCode }); }; // 業務接口 async function BaseApi( opt = {}, { prefix = "", codeField = "code", // dataField = "data", codeNum = 200, msgField = "msg", tipsCode = "code" } ) { opt = handlerData(opt, { prefix }); // 參數預處理 const error = opt.error ?? true; // 默認,提示錯誤信息 const success = opt.success ?? false; // 默認:不提示成功信息 // 特殊格式請求處理 const posts = ["put", "post", "patch"]; if ( posts.includes(opt.method) && opt.headers["Content-Type"] === "application/x-www-form-urlencoded" ) { opt.data = qs.stringify(opt.data); } try { const result = await ajax(opt); // 請求接口 if (result.headers["authorization"]) { // vuex.commit("user/SET_TOKEN", result.headers["authorization"]); } // 是否已登錄 if (opt.reLogin && result.status === 401) { signOut(); return Promise.reject(result); } switch (opt.file) { case false: { // 解密后端返回信息 /*const response = opt.mock ? result.data : result.data ? JSON.parse(base64Decode(result.data)) : result.data;*/ const response = result.data; const code = response[codeField]; // const data = response[dataField]; const message = response[msgField]; const errCode = response[tipsCode]; // 提前統一處理接口提示信息 if (code === codeNum) { handlerSuccessMessage(success, message); // success===false:不提示信息 return Promise.resolve(response); } else { handlerErrorMessage(error, message, errCode); // error===false:不提示信息 return Promise.reject(response); } } // 走文件模式下 case true: { return Promise.resolve(result); } } } catch (e) { const response = e.response; if (opt.reLogin && response?.status === 401) signOut(); else { const resData = response?.data ?? {}; const message = resData[msgField]; const errCode = resData[tipsCode]; handlerErrorMessage(error, message, errCode); } return Promise.reject(e); } } export { BaseApi }; ``` * axiosAjax.js文件 ``` import axios from "axios"; import jsonpAjax from "./jsonpAjax"; import { Loading } from "element-ui"; // axios函數封裝 const ajax = async ({ url = "", loading = false, // 加載攔截 baseURL = "", data = {}, params = {}, // 地址欄拼接數據,僅限于'put', 'post', 'patch' headers = { "Content-Type": "application/json;charset=UTF-8" }, // 頭部信息處理 method = "get", timeout = 30 * 1000, responseType = "json", // 表示服務器響應的數據類型,可以是 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream' jsonp = false, //是否使用jsonp請求接口 jsonpOpt = {} // jsonp庫的options參數 }) => { // 接口全局加載提示 let loadingInstance = ""; if (loading !== false) { loadingInstance = Loading.service({ lock: true, text: loading !== true ? loading : "加載中……", spinner: "el-icon-loading", background: "rgba(0, 0, 0, 0.5)" }); } try { const posts = ["put", "post", "patch"]; // 使用data作為發送數據主體 let response = null; if (jsonp) { response = await jsonpAjax({ url, baseURL, data, timeout, jsonpOpt }); } else { response = await axios({ url: url, baseURL: baseURL, headers: headers, method: method, params, [posts.includes(method.toLowerCase()) ? "data" : "params"]: data, timeout: timeout, responseType }); } loadingInstance && loadingInstance.close(); return Promise.resolve(response); } catch (e) { loadingInstance && loadingInstance.close(); return Promise.reject(e); } }; export { ajax }; ``` * jsonpAjax.js文件 ``` // 原始文檔https://github.com/webmodules/jsonp import jsonp from "jsonp"; function connectUrl(data) { let url = ""; for (let k in data) { let value = data[k] !== undefined ? data[k] : ""; url += `&${k}=${encodeURIComponent(value)}`; //使用的es6的模板字符串的用法 ${} } return url ? url.substring(1) : ""; //這里主要判斷data是否為空 } const handlerOpt = ({ url = "", baseURL = "", // 將會拼接到url前面 data = {}, // 傳入的參數,注意是對象 timeout = 60 * 1000, jsonpOpt = {} }) => { url = baseURL + url; // 拼接基礎路徑 //拼接字符串(根路徑 + 參數),看根路徑是否包含 ‘?’ url = url + (url.indexOf("?") < 0 ? "?" : "&") + connectUrl(data); jsonpOpt = { // param 用于指定回調的查詢字符串參數的名稱(默認為callback) // prefix 處理 jsonp 響應的全局回調函數的前綴(默認為__jp) // name 處理 jsonp 響應的全局回調函數的名稱(默認為prefix+ 遞增計數器) timeout, //發出超時錯誤后多長時間。0禁用(默認為60000) ...jsonpOpt }; return { url, baseURL, data, timeout, jsonpOpt }; }; //封裝一個jsonp的函數 export default function jsonpAjax(opt = {}) { let { url, jsonpOpt } = handlerOpt(opt); return new Promise((resolve, reject) => { jsonp(url, jsonpOpt, (err, data) => { if (!err) { resolve(data); } else { reject(err); } }); }); } ``` * tips.js ``` import { Message } from "element-ui"; // import { checkAnswer } from '@/utils/jumpToSolution' // 統一message const customMessage = async ({ msg = "", type = "success", tipsCode = "" }) => { if (!msg) return null; if (!tipsCode) { Message({ message: msg, type, showClose: true }); } if (tipsCode) { Message({ dangerouslyUseHTMLString: true, message: `${msg} <a href="/nbs-pc/#/wiki-search?name=${tipsCode}" style="color: #409EFF;" target="_blank">更多幫助</a>`, type, showClose: true }); // let showTip = await checkAnswer(tipsCode) // if (showTip) { // Message({ // dangerouslyUseHTMLString: true, // message: `${msg} <a href="/nbs-pc/#/wiki-search?name=${tipsCode}" style="color: #409EFF;" target="_blank">更多幫助</a>`, // type, // showClose: true, // }) // } else { // Message({ // message: msg, // type, // showClose: true, // }) // } } }; // 消息提示 const Tips = { success(opt = {}) { customMessage({ type: "success", ...opt }); }, error(opt = {}) { customMessage({ type: "error", ...opt }); } }; export default Tips; ``` * upload.js文件 ``` // 適用于按鈕點擊上傳場景 import Tips from "./tips"; // 對uri地址進行數據拼接 const new_url = obj => { if (obj) { let fields = ""; for (let key in obj) { fields = fields + `&${key}=${obj[key]}`; } return "?" + fields.substring(1, fields.length); } else { return ""; } }; const paramsHandle = options => { options.baseURL = ""; //個人處理,需要兼容之前的elementui等插件的上傳 options.fdata = options.fdata || ""; //文件上傳的url拼接地址 options.success = options.success || "文件上傳成功"; options.url = options.url + new_url(options.fdata); options.loading = options.loading || "文件上傳中"; options.headers = options.headers || {}; options.headers["Content-Type"] = "multipart/form-data"; options.method = "post"; options.multiple = options.multiple || false; //是否多文件,默認false //文件類型驗證,注意傳入數組,默認["image/jpeg", "image/png"] options.type = options.type || ["image/jpeg", "image/png"]; options.size = options.size || 5; //文件大小限制,默認5M大小 options.max = options.max || 5; //最多上傳幾個文件 return options; }; // 文件上傳 const upload = (ajaxCallback, params) => { const options = paramsHandle(params); //文件驗證處理 let input = document.createElement("input"); input.type = "file"; options.multiple ? (input.multiple = "multiple") : ""; input.click(); return new Promise((suc, err) => { let type = options.type; input.addEventListener("input", watchUpload, false); function watchUpload(event) { //console.log(event); //移除監聽 let remove = () => { input.removeEventListener("input", watchUpload, false); input = null; }; const file = event.path[0].files; const len = file.length; // 文件數量限制 if (len > options.max) { remove(); Tips.error({ msg: "文件個數超過" + options.max }); err(file); return false; } let formData = new FormData(); for (let i = 0; i < len; i++) { // 文件大小限制 if (options.size !== 0 && file[i].size / 1024 / 1024 > options.size) { remove(); Tips.error({ msg: file[i].name + "文件超過" + options.size + "M" }); err(file[i]); return false; } // 文件類型限制 if (type.length > 0 && !type.includes(file[i].type)) { remove(); Tips.error({ msg: file[i].name + "文件類型為" + file[i].type }); err(file); return false; } formData.append("dhtUpload", file[i], file[i].name); } options.data = formData; // 最終進行文件上傳 ajaxCallback(options) .then(e => { suc(e); }) .catch(e => { err(e); }); // 沒有問題下,清空監聽。 remove(); } }); }; export default upload; ``` ## 其他 防抖節流antiShakingAndThrottling.js,請[點擊](http://www.hmoore.net/vvmily_king/vvmily/2331774)前往。 倉庫地址:https://github.com/wwmingly/axios-services
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看