• 前端请求后台接口失败处理逻辑


    前后分离项目,前端为uni-app(vue2),后台为java

    后台api设置存在问题,部分公共接口为开放非登录用户访问权限

    导致前台打开首页后立即跳转到登录提示页

    怀疑是开了uni-app开发代理服务器,导致访问的代理服务器地址被拦截:

    http://localhost:3030/api/bms/getPostPageList?page=1&limit=12&hot=1

    由于不能通过单步执行,查找执行过程,只能在拦截代码中盲猜,始终未找到匹配的代码过程:

    1. import Vue from 'vue'
    2. import App from './App'
    3. import store from './store'
    4. import * as Db from './common/db.js'
    5. import $AppEntryController from './AppEntryController.js'
    6. import * as $apis from './apis/index.js'
    7. import $mRouter from './common/router.js'
    8. import $mUtils from './common/utils.js'
    9. import $mConfig from "./config/index.config.js"
    10. import $mAssetsPath from './config/assets.config.js'
    11. import $mRoutesConfig from './config/routes.config.js'
    12. import $mConstDataConfig from './config/constData.config.js'
    13. import $modalHelper from './common/modalHelper.js'
    14. import mPageView from "./components/m-page-view/m-page-view.vue"
    15. Vue.component("yzb-page", mPageView)
    16. const prePage = ()=>{
    17. let pages = getCurrentPages();
    18. let prePage = pages[pages.length - 2];
    19. // #ifdef H5
    20. return prePage;
    21. // #endif
    22. return prePage.$vm;
    23. }
    24. Vue.prototype.$mPage ={prePage};
    25. Vue.config.productionTip = false;
    26. Vue.prototype.$AppEntryController = $AppEntryController;
    27. Vue.prototype.$store =store;
    28. Vue.prototype.$apis = $apis;
    29. Vue.prototype.$mRouter = $mRouter;
    30. Vue.prototype.$mUtils = $mUtils;
    31. Vue.prototype.$mConfig = $mConfig;
    32. Vue.prototype.$mAssetsPath = $mAssetsPath;
    33. Vue.prototype.$mRoutesConfig = $mRoutesConfig;
    34. Vue.prototype.$mConstDataConfig = $mConstDataConfig;
    35. Vue.prototype.$modalHelper = $modalHelper;
    36. Vue.prototype.$db = Db;
    37. import GoEasy from "./lib/goeasy-2.4.7.min.js";
    38. const goEasy = GoEasy.getInstance({
    39. host:"hangzhou.goeasy.io",//应用所在的区域地址: 【hangzhou.goeasy.io |singapore.goeasy.io】
    40. appkey:"BC-88a9b720d97c4de88eefd2d64daf3fd0", // common key,
    41. modules:["im"],
    42. // true表示支持通知栏提醒,false则表示不需要通知栏提醒
    43. allowNotification:true //仅有效于app,小程序和H5将会被自动忽略
    44. });
    45. Vue.prototype.GoEasy = GoEasy;
    46. Vue.prototype.goEasy = goEasy;
    47. $mRouter.beforeEach((navType, to) => {
    48. if (to.route === undefined) throw ("路由钩子函数中没有找到to.route对象,路由信息:" + JSON.stringify(to));
    49. console.log("进入路由过滤器")
    50. console.log("to=",to)
    51. if (to.route.path === $mRoutesConfig.login.path && store.getters.hasLogin) {
    52. uni.redirectTo({
    53. url: $mUtils.objParseUrlAndParam($mRoutesConfig.main.path, to.query)
    54. })
    55. return;
    56. }
    57. // 过滤需要权限的页面
    58. if (to.route.requiresAuth) {
    59. if (store.getters.hasLogin) {
    60. // 已经登录
    61. uni[navType]({
    62. url: $mUtils.objParseUrlAndParam(to.route.path, to.query)
    63. })
    64. } else {
    65. // 登录成功后的重定向地址和参数
    66. let query = {
    67. redirectUrl: to.route.path,
    68. ...to.query
    69. }
    70. // 没有登录 是否强制登录?
    71. if (store.state.forcedLogin) {
    72. //#ifdef H5
    73. uni.redirectTo({
    74. url: $mUtils.objParseUrlAndParam($mRoutesConfig.loginPwd.path, query)
    75. })
    76. // #endif
    77. //#ifdef MP-WEIXIN
    78. uni.redirectTo({
    79. url: $mUtils.objParseUrlAndParam($mRoutesConfig.login.path, query)
    80. })
    81. // #endif
    82. } else {
    83. //#ifdef H5
    84. uni.redirectTo({
    85. url: $mUtils.objParseUrlAndParam($mRoutesConfig.loginPwd.path, query)
    86. })
    87. // #endif
    88. //#ifdef MP-WEIXIN
    89. uni.redirectTo({
    90. url: $mUtils.objParseUrlAndParam($mRoutesConfig.login.path, query)
    91. })
    92. // #endif
    93. }
    94. }
    95. } else {
    96. uni[navType]({
    97. url: $mUtils.objParseUrlAndParam(to.route.path, to.query)
    98. })
    99. }
    100. })
    101. App.mpType = 'app'
    102. const app = new Vue({
    103. store,
    104. ...App
    105. })
    106. app.$mount()
    107. Vue.prototype.formatDate = function (t) {
    108. t = t || Date.now();
    109. let time = new Date(t);
    110. let str = time.getMonth() < 9 ? ('0' + (time.getMonth() + 1)) : (time.getMonth() + 1);
    111. str += '-';
    112. str += time.getDate() < 10 ? ('0' + time.getDate()) : time.getDate();
    113. str += ' ';
    114. str += time.getHours();
    115. str += ':';
    116. str += time.getMinutes() < 10 ? ('0' + time.getMinutes()) : time.getMinutes();
    117. return str;
    118. }
    119. // 控制全局日志开关
    120. // console.log = (function (oriLogFunc) {
    121. // return function () {
    122. // //判断配置文件是否开启日志调试
    123. // if (!true) {
    124. // try{
    125. // oriLogFunc.call(console, ...arguments);
    126. // }catch(e){
    127. // console.error('console.log error', e);
    128. // }
    129. // }
    130. // }
    131. // })(console.log);

    重新查看uni-app发送http请求的代码段,发现在后台返回401时,代码直接跳转到登录流程:

    1. import store from "@/store"
    2. function HTTP(obj, config) {
    3. let defaultConfig = {
    4. isRes: false,
    5. loading: false
    6. }
    7. config = { ...defaultConfig,
    8. ...config
    9. }
    10. // 如果需要显示loading,mask防止点击穿透
    11. config.loading && uni.showLoading({
    12. title: '加载中',
    13. mask: true
    14. });
    15. return new Promise((resolve, reject) => {
    16. let options = {
    17. url: "",
    18. method: "GET",
    19. data: {},
    20. dataType: "json",
    21. header: {
    22. "content-type": "application/json",
    23. "X-requested-With": "XMLHttpRequest",
    24. // 模拟用户登录
    25. //"X-Access-Token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2OTQ1MjM5NDEsInVzZXJuYW1lIjoiYWRtaW4ifQ.iGxw-j0uNi-rY96KuP9B4Jgx-t-Uk2mYZxVWMb7ySbo"
    26. },
    27. success: (res) => {
    28. //console.log("HTTP请求结果:",res)
    29. //console.log("resolve:",resolve)
    30. uni.hideLoading();
    31. // 状态码为200
    32. if (res.statusCode == 200) {
    33. let data = res.data;
    34. //自动校验用户是否登录过期
    35. if (data.code == "01") {
    36. store.dispatch("reLogin");
    37. return;
    38. }
    39. //返回 { code:10000,msg:"消息",data:[] }
    40. if (config.isRes) {
    41. resolve(data)
    42. }
    43. // 返回 data:[]
    44. else {
    45. if (data.code == "200") {
    46. //console.log("data对象:",data)
    47. resolve(data.result||true)
    48. } else {
    49. wx.showToast({
    50. title: data.message,
    51. icon: "none",
    52. duration: 2000
    53. })
    54. reject(data.message);
    55. }
    56. }
    57. }else if(res.statusCode == 401) {
    58. store.dispatch("reLogin");
    59. return;
    60. } else {
    61. reject("HTTP:状态码异常!");
    62. }
    63. },
    64. fail: (err) => {
    65. uni.hideLoading();
    66. uni.showToast({
    67. title: "网络异常,请稍后再试!",
    68. icon: "none",
    69. })
    70. reject("网络异常,请稍后再试!");
    71. },
    72. complete: () => {}
    73. }
    74. options = { ...options,
    75. ...obj
    76. };
    77. const OPENID = uni.getStorageSync("openId");
    78. const Token=uni.getStorageSync("token");
    79. // const location=uni.getStorageSync("location");
    80. // if(location){
    81. // //所有接口带上当前位置信息
    82. // options["data"]["latitude"] = location.latitude;
    83. // options["data"]["longitude"] = location.longitude;
    84. // options["data"]["pcitycode"] = location.pcitycode;
    85. // }
    86. console.log("Token==="+Token);
    87. if (OPENID) options["header"]["openId"] = OPENID;
    88. if (Token) options["header"]["X-Access-Token"] = Token;
    89. if (options.url && options.method) {
    90. wx.request(options);
    91. } else {
    92. wx.showToast({
    93. title: 'HTTP:缺失参数',
    94. icon: "none",
    95. duration: 2000
    96. })
    97. }
    98. })
    99. }
    100. export default {
    101. GET(url, data = {}, config) {
    102. return HTTP({
    103. url,
    104. data,
    105. method: "GET"
    106. }, config);
    107. },
    108. POST(url, data = {}, config) {
    109. return HTTP({
    110. url,
    111. data,
    112. method: "POST"
    113. }, config);
    114. },
    115. POSTformdata(url, data = {}, config) {
    116. return HTTP({
    117. url,
    118. data,
    119. method: "POST"
    120. }, config);
    121. }
    122. }

    这个过程对用户不友好,应提示用户未登录无法查看数据,让用户确认跳转还是留在原始位置。

    解决办法是,使用wx.showModal(显示选择的对话框-带按钮),添加如下代码:

    1. else if(res.statusCode == 401) {
    2. let res_message = res.data.message // 因为wx.showModal也有res,需要另存变量名
    3. wx.showModal({
    4. title: '是否需要登录?',
    5. content: '提示:'+res_message,
    6. complete: (res) => {
    7. if (res.cancel) {
    8. reject(res_message);
    9. }
    10. if (res.confirm) {
    11. store.dispatch("reLogin");
    12. }
    13. }
    14. })
    15. // 这不是正常的promise流程,添加这段代码的人不是原作者
    16. // store.dispatch("reLogin");
    17. // return;
    18. }

    为了适应h5页面或小程序,添加条件编译:

    效果:

     点确定则跳转到登录页面,点取消则留在当前页面。

    参考:

    https://www.cnblogs.com/guanxinjing/p/17337941.html

    跨端兼容 | uni-app官网

    注意uni-app条件编译不需要在配置文件设置条件未MP-WEIXIN或者H5,在编译时自动判断。

  • 相关阅读:
    C语言学习(六)函数
    kafka3.X集群安装(不使用zookeeper)
    第二章 USB应用笔记之USB通讯基础
    可视化设计:一文读懂桑基图,从来处来,到去出去。
    Apache Paimon系列之:认识Paimon
    asp.net C#免费反编译工具ILSpy
    前端vue element axios混编团队发送数据到后端,后端接受使用的是$_POST
    Linux下用rm误删除文件的三种恢复方法
    undefined symbol: __gmpz_limbs_write 问题分析和解决
    ElasticSearch之Quick.ElasticSearch.Furion组件的使用
  • 原文地址:https://blog.csdn.net/qq_27361945/article/details/134015012