vue項目token放在哪里_關于vue動態菜單的那點事

vue-element-admin4.0國內節點訪問地址:https://panjiachen.gitee.io/vue-element-admin-site/zh/

本此使用的是https://github.com/PanJiaChen/vue-element-admin/tree/i18n 國際化分支的版本。說是除了國際化其他都一樣。

本文主要介紹前臺動態的使用資源權限。

  • 后臺使用springboot2搭建項目就不說了,百度一下一大堆。
  • 前臺開發前需要安裝一下nodejs,這里注意一下nodejs和npm的版本要相互匹配,否則在編譯的時候會報錯。

打開項目后需要安裝一下依賴的模塊。

npm install

  • 1、全局請求配置的修改。

src/utils/request.js 當然也有用src/utils/request-axios.js的 修改方式大同小異zhe'li

import axios from 'axios'// import { MessageBox, Message } from 'element-ui'import { MessageBox, Message } from 'element-ui'import store from '@/store'import { getToken, removeToken } from '@/utils/auth' const qs = require('querystring') create an axios instanceconst service =    axios.create({  baseURL: process.env.VUE_APP_BASE_API,                  url = base url + request url                  withCredentials: true,                  send cookies when cross-domain requests  timeout: 5000,                  request timeout  jsonData: false}) request interceptorservice.interceptors.request.use(    config => {        if (store.getters.token) {          let each request carry token            ['X-Token'] is a custom headers key           please modify it according to the actual situation            config.headers['X-Token'] = getToken()    }         if (config.method.toLowerCase() === 'get') {            config.params = config.data    }    else if (config.method.toLowerCase() === 'post') {            if (config.jsonData) {               config.headers['Content-Type'] = 'application/json;charset=UTF-8'                config.data = JSON.stringify(config.data)      }       else {               config.headers['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8'               config.data = qs.stringify(config.data)      }       }       console.log(config) // for debug        return config  },  error => {          // do something with request error         console.log(error)       // for debug          return Promise.reject(error)  }) // response interceptorservice.interceptors.response.use(    /**   * If you want to get http information such as headers or status   *  Please return  response => response   */    /**   * Determine the request status by custom code   * Here is just an example     * You can also judge the status by HTTP Status Code   */  r  esponse => {    const res = response.data    // code==2000是業務邏輯成功,其他的返回code都是業務邏輯錯誤    if (res.code === 5002) {      // to re-login      // token過期或者密碼被修改了都需要重新獲取token      MessageBox.confirm('You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', {        confirmButtonText: 'Re-Login',        cancelButtonText: 'Cancel',        type: 'warning'      }).then(() => {        store.dispatch('user/resetToken').then(() => {          location.reload()        })      })    } else {      return res    }  },  error => {    // console.log('err' + error) // for debug    Message({      message: error.message,      type: 'error',      duration: 5 * 1000    })    removeToken()    if (error.response && error.response.status === 403) {      this.$router.push(`/login?redirect=${this.$route.fullPath}`)    }    return Promise.reject(error)  }) export default service

這個文件修改的主要是get、post請求傳遞參數的設置。

get使用params傳遞參數。post就data

還有就是form數據需要轉化,使用qs.stringify來轉換。轉化成A=1&B=2&c=3這樣的形式。

  • 2、后臺接口路徑的配置。

api請求都放在一個文件下面,這樣以后維護比較方便

b4ffbbe4e973874fa2264a3d30ab75ee.png
1d4cddc9a448ec8038b264d1390fa07e.png

至于請求后臺方法每個界面一個方法,例如這樣

a3d18be25ccca604f6eb81f400f84024.png

頁面調用方法需要引用,類似這種

c614a7dd3f8788fb4e74c0054ddbe638.png
export default {  name: 'user-list',  components: { Pagination },  directives: { waves },  filters: {    statusFilter(status) {      const statusMap = {        published: 'success',        draft: 'info',        deleted: 'danger'      }      return statusMap[status]    },    typeFilter(type) {      return calendarTypeKeyValue[type]    }  },  data() {    return {      tableKey: 0,      list: null,      total: 0,      listLoading: true,      listQuery: {        page: 1,        limit: 20,        importance: undefined,        title: undefined,        type: undefined,        username: undefined,        deptname: undefined,        rolename: undefined      },      calendarTypeOptions,      showReviewer: false,      temp: {        id: undefined,        remark: '',        username: '',        rolename: '',        deptid: '',        roleid: '',        password: ''      },      dialogFormVisible: false,      dialogCzmmVisible: false,      dialogStatus: '',      textMap: {        update: '修改用戶',        create: '新增用戶'      },      pvData: [],      rules: {        username: [{ required: true, message: '必填項', trigger: 'change' }],        loginname: [{ required: true, message: '必填項', trigger: 'change' }],        deptid: [{ required: true, message: '必選項', trigger: 'change' }],        roleid: [{ required: true, message: '必選項', trigger: 'change' }],        password: [{ required: true, message: '必選項', trigger: 'change' }, { min: 6, max: 30, message: '長度在 6 到 30 個字符', trigger: 'change' }]      },      downloadLoading: false,      deptOptions: [],      roleOptions: []    }  },  created() {    this.getList()  },  methods: {    getList() {      this.listLoading = true      fetchList(this.listQuery).then(response => {        debugger        this.list = response.attributes.list.list        this.total = response.attributes.list.total        this.listLoading = false      })    },    handleFilter() {      this.listQuery.page = 1      this.getList()    },    resetTemp() {      this.temp = {        id: undefined,        remark: '',        username: '',        rolename: '',        deptid: '',        roleid: '',        password: ''      }    },    handleCreate() {      this.resetTemp()      this.dialogStatus = 'create'      this.dialogFormVisible = true      this.$nextTick(() => {        this.$refs['dataForm'].clearValidate()      })      fetchRoleOptions().then(response => {        this.roleOptions = response.attributes.list      })      var aa = {        code: 'dept'      }      fetchDicePropOptions(aa).then(response => {        this.deptOptions = response.attributes.list      })    },    createData() {      this.$refs['dataForm'].validate((valid) => {        if (valid) {          const tempData = Object.assign({}, this.temp)          saveSysUser(qs.stringify(tempData)).then(() => {            this.dialogFormVisible = false            this.$notify({              title: '提示',              message: '保存成功!',              type: 'success',              duration: 2000            })            this.getList()          })        }      })    },    handleUpdate(row) {      this.temp = Object.assign({}, row) // copy obj      this.temp.roleid = Number(this.temp.roleid)      this.temp.deptid = Number(this.temp.deptid)      this.dialogStatus = 'update'      this.dialogFormVisible = true      this.$nextTick(() => {        this.$refs['dataForm'].clearValidate()      })      fetchRoleOptions().then(response => {        this.roleOptions = response.attributes.list      })      var aa = {        code: 'dept'      }      fetchDicePropOptions(aa).then(response => {        this.deptOptions = response.attributes.list      })    },    updateData() {      this.$refs['dataForm'].validate((valid) => {        if (valid) {          const tempData = Object.assign({}, this.temp)          updateSysUser(qs.stringify(tempData)).then(() => {            this.dialogFormVisible = false            this.$notify({              title: '提示',              message: '保存成功!',              type: 'success',              duration: 2000            })            this.getList()          })        }      })    },    handleDelete(row, index) {      deleteSysUser(row.id).then(response => {        this.dialogFormVisible = false        this.$notify({          title: '提示',          message: '刪除成功!',          type: 'success',          duration: 2000        })        this.getList()      })    },    handleReloadPassword() {      if (this.temp.password === '') {        this.$notify({          title: '提示',          message: '密碼不能為空!',          type: 'error',          duration: 2000        })        return      }      var date = {        id: this.temp.id,        password: this.temp.password      }      reloadPassword(date).then(response => {        if (response.code > 0) {          this.dialogCzmmVisible = false          this.$notify({            title: '提示',            message: '重置密碼成功!',            type: 'success',            duration: 2000          })        }      })    },    handleRefresh() {      this.listQuery.username = ''      this.listQuery.rolename = ''      this.listQuery.deptname = ''    },    formatJson(filterVal) {      return this.list.map(v => filterVal.map(j => {        if (j === 'timestamp') {          return parseTime(v[j])        } else {          return v[j]        }      }))    },    indexMethod(index) {      return index + 1    },    handleCz(row) {      this.resetTemp()      this.dialogCzmmVisible = true      this.temp.id = row.id      this.$nextTick(() => {        this.$refs['dataFormCx'].clearValidate()      })    }  }}import qs from 'qs'

方法調用就像這種這么做就可以

3 、 登錄設置角色信息、過濾路由(根據角色動態的生成菜單)

  • store/user.js
import { loginByPwd, logout, getLoginUserInfo } from '@/api/user'import { getToken, setToken, removeToken } from '@/utils/auth'import router, { resetRouter } from '@/router' const state = {    token: getToken(),    name: '',  avatar: '',   introduction: '',    roles: []} c  onst mutations = {  SET_TOKEN: (state, token) => {    state.token = token  },  SET_INTRODUCTION: (state, introduction) => {    state.introduction = introduction  },  SET_NAME: (state, name) => {    state.name = name  },  SET_AVATAR: (state, avatar) => {    state.avatar = avatar  },  SET_ROLES: (state, roles) => {    state.roles = roles  }} const actions = {  // user login  loginByPwd({ commit }, userInfo) {    const { userName, passWord } = userInfo     return new Promise((resolve, reject) => {      loginByPwd({ userName: userName.trim(), passWord: passWord }).then(response => {        if (response.code === 2000) {          commit('SET_TOKEN', response.data)          setToken(response.data)        }        resolve(response)      }).catch(error => {        reject(error)      })    })  },   // get user info  getLoginUserInfo({ commit, state }) {    return new Promise((resolve, reject) => {      getLoginUserInfo(state.token).then(response => {        // const { data } = response         // console.log('getLoginUserInfo', response)         if (!response) {          reject('Verification failed, please Login again.')        }         if (response.resultFlag) {          commit('SET_ROLES', response.data.roleList)          commit('SET_NAME', response.data.likeName)          commit('SET_AVATAR', response.data.imgUrl)          commit('SET_INTRODUCTION', '我是一個超級管理員哦')          // 一個用戶可能有多個角色,這里返回的是角色的集合信息          // let allRole = response.data.roleList           resolve(response)        } else {          console.error('獲取當前登錄用戶信息出錯了')        }      }).catch(error => {        reject(error)      })    })  },   // user logout  logout({ commit, state }) {    return new Promise((resolve, reject) => {      logout(state.token).then(() => {        commit('SET_TOKEN', '')        commit('SET_ROLES', [])        removeToken()        resetRouter()        resolve()        location.reload()      }).catch(error => {        reject(error)      })    })  },   // remove token  resetToken({ commit }) {    return new Promise(resolve => {      commit('SET_TOKEN', '')      commit('SET_ROLES', [])      removeToken()      resolve()    })  },   // dynamically modify permissions  changeRoles({ commit, dispatch }, role) {    return new Promise(async resolve => {      const token = role + '-token'       commit('SET_TOKEN', token)      setToken(token)       const { roles } = await dispatch('getInfo')       resetRouter()       // generate accessible routes map based on roles      const accessRoutes = await dispatch('permission/generateRoutes', roles, { root: true })       // dynamically add accessible routes      router.addRoutes(accessRoutes)       // reset visited views and cached views      dispatch('tagsView/delAllViews', null, { root: true })       resolve()    })  }} export default {  // namespaced: true,  state,  mutations,  actions}

這個文件就是登錄,成功后獲取當前用戶擁有的資源信息。

當然下載下來的這個文件菜單權限是寫死的是直接使用roles來做的判斷,就是在router.js文件中直接把菜單需要的角色設置在里邊。

缺點是添加了角色就要修改代碼打包發布。這簡直是災難。

所以這里面將原系統修改了一下實現動態菜單讀取,就好多了

vue-element-admin-mastersrcouterindex.jsimport Vue from 'vue'import Router from 'vue-router'Vue.use(Router)/* Layout */import Layout from '@/layout'/* Router Modules */// import componentsRouter from './modules/components'// import chartsRouter from './modules/charts'// import tableRouter from './modules/table'// import nestedRouter from './modules/nested'export const constantRoutes = [  {    path: '/redirect',    component: Layout,    hidden: true,    children: [      {        path: '/redirect/:path*',        component: () => import('@/views/redirect/index')      }    ]  },  {    path: '/login',    component: () => import('@/views/login/index'),    hidden: true  },  {    path: '/auth-redirect',    component: () => import('@/views/login/auth-redirect'),    hidden: true  },  {    path: '/',    component: Layout,    redirect: '/dashboard',    children: [      {        path: 'dashboard',        component: () => import('@/views/dashboard/index'),        name: 'Dashboard',        meta: { title: 'dashboard', icon: 'dashboard', affix: true }      }    ]  }]/** * asyncRoutes * the routes that need to be dynamically loaded based on user roles */export const asyncRoutes = [  /** when your routing map is too long, you can split it into small modules **/  // componentsRouter,  // chartsRouter,  // nestedRouter,  // tableRouter,  // 404 page must be placed at the end !!!]const createRouter = () => new Router({  // mode: 'history', // require service support  mode: 'hash',  scrollBehavior: () => ({ y: 0 }),  routes: constantRoutes})const router = createRouter()// Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465export function resetRouter() {  const newRouter = createRouter()  router.matcher = newRouter.matcher // reset router}export default router

首先先將靜態路由調好,一些常用的不需要權限的先加上

然后找到srcpermission.js

import router, { resetRouter } from '@/router'import store from './store'import { Message } from 'element-ui'import NProgress from 'nprogress' // progress barimport 'nprogress/nprogress.css' // progress bar styleimport { getToken } from '@/utils/auth' // get token from cookieimport getPageTitle from '@/utils/get-page-title'NProgress.configure({ showSpinner: false }) // NProgress Configurationconst whiteList = ['/login', '/auth-redirect'] // no redirect whitelistlet add1 = falseconst matched1 = falserouter.beforeEach(async(to, from, next) => {  // start progress bar  NProgress.start()  // set page title  document.title = getPageTitle(to.meta.title)  // determine whether the user has logged in  const hasToken = getToken()  if (hasToken) {    if (to.path === '/login') {      // if is logged in, redirect to the home page      next({ path: '/' })      NProgress.done()    } else {      // determine whether the user has obtained his permission roles through getInfo      const hasRoles = store.getters.roles && store.getters.roles.length > 0      if (hasRoles) {        next()      } else {        try {          // get user info          // note: roles must be a object array! such as: ['admin'] or ,['developer','editor']          // const { roles } = await store.dispatch('user/getInfo')          // generate accessible routes map based on roles          debugger          // const fromPath = GetUrlRelativePath(window.location.href)          if (!add1) {            //注意在這里,將后臺拼裝好的功能菜單添加到當前路由中,切記一定要加變量控制            //不然會死循環,如果誰有好的解決辦法請回復我謝謝            // router.resetRouter()            let accessRoutes = []            accessRoutes = await store.dispatch('permission/getAuthMenu')             router.addRoutes(accessRoutes)            add1 = true            // hack method to ensure that addRoutes is complete            // set the replace: true, so the navigation will not leave a history record            next({ ...to, replace: true })          } else {            // debugger            // if (to.matched.length === 0) {            //   router.resetRouter()            //   let accessRoutes = []            //   accessRoutes = await store.dispatch('permission/getAuthMenu')            //   router.addRoutes(accessRoutes)            //   next({ ...to, replace: true })            // } else {              next()            // }          }        } catch (error) {          // remove token and go to login page to re-login          await store.dispatch('user/resetToken')          Message.error(error || 'Has Error')          next(`/login?redirect=${to.path}`)          NProgress.done()        }      }    }  } else {    /* has no token*/    if (whiteList.indexOf(to.path) !== -1) {      // in the free login whitelist, go directly      next()    } else {      // other pages that do not have permission to access are redirected to the login page.      next(`/login?redirect=${to.path}`)      NProgress.done()    }  }})export function GetUrlRelativePath(url) {  var arrUrl = url.split('//')  var start = arrUrl[1].indexOf('/')  var relUrl = arrUrl[1].substring(start)  if (relUrl.indexOf('?') !== -1) {    relUrl = relUrl.split('?')[0]  }  return relUrl}router.afterEach(() => {  // finish progress bar  NProgress.done()})
import { asyncRoutes, constantRoutes } from '@/router'const state = {  routes: [],  roles: [],  username: '',  addRoutes: [],  isChange: false}const mutations = {  isChange: (state, isChanged) => {    state.isChange = isChanged  },  SET_USER: (state, username) => {    state.username = username  },  SET_ROLES: (state, roles) => {    state.roles = roles  },  SET_ROUTES: (state, routes) => {    state.addRoutes = routes    state.routes = constantRoutes.concat(routes)  }}export function formatMenus(routes, data) {  data.forEach(item => {    const menu = {}    menu.path = '/' + item.path    menu.name = item.name    menu.component = Layout    menu.redirect = '/'    menu.meta = { title: item.title, icon: 'excel', noCache: false }    if (item.children.length > 0) {      menu.children = []      item.children.forEach(item1 => {              if (item1.name === 'examinationInfo') {          const menu1 = {}          menu1.path = 'detail'          menu1.component = resolve => require(['@/views/' + item1.component + '/' + item1.path + '.vue'], resolve)          menu1.name = 'examinationInfo'          menu1.meta = { title: item1.title, noCache: false, activeMenu: '@/views/Examination/examination' }          menu1.hidden = true          menu.children.push(menu1)        }        else {          const menu1 = {}          menu1.path = item1.path          menu1.component = resolve => require(['@/views/' + item1.component + '/' + item1.path + '.vue'], resolve)          menu1.name = item1.name          menu1.meta = { title: item1.title }          menu.children.push(menu1)        }      })    }    debugger    routes.push(menu)  })}const actions = {  getAuthMenu({ commit }) {    return new Promise(resolve => {      getAuthMenu({}).then(response => {        const data = response.attributes.menus        const roles = response.attributes.rolesgetAuthMenu        const username = response.attributes.username        formatMenus(asyncRoutes, data)        commit('SET_ROUTES', asyncRoutes)        commit('SET_ROLES', roles)        commit('SET_USER', username)        // const isChanged = true        // commit('isChange', isChanged)        asyncRoutes.push({ path: '*', redirect: '/404', hidden: true })        //注意404界面一定要加載最后,不然會報錯        resolve(asyncRoutes)      })    })  }}export default {  namespaced: true,  state,  mutations,  actions}import Layout from '@/layout'import { getAuthMenu } from '@/api/user'

在請求頭部如果需要添加cookie

f9c0827520b69f7017c71e9f070782b3.png

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/453766.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/453766.shtml
英文地址,請注明出處:http://en.pswp.cn/news/453766.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

H264學習方法歷程資料

我的H.264學習歷程 半年前,我知道了H.264這個名詞。那個時候決定學習H.264,可是我連資料都不知道如何收集。而且整個學校就只有我一個人在學習H.264, 找不到人交流,所以那個時候學得真的是舉步維艱,很痛苦&#xff0c…

深度學習之 ROI Pooling

什么是ROI? ROI是 Region of interest 的簡寫,指的是 Faster R-CNN 結構中,經過 RPN 層后,產生的 proposal 對應的 box 框。 ROI Pooling 顧名思義,是 pooling 層的一種,而且是針對 ROIs 的 pooling。整個…

KD樹小結

很久之前我就想過怎么快速在二維平面上查找一個區域的信息,思考許久無果,只能想到幾種優秀一點的暴力。 KD樹就是干上面那件事的。 別的不多說,趕緊把自己的理解寫下來,免得涼了。 KD樹的組成 以維護k維空間(x,y,……)內的KD樹為例…

多元函數求極值中的a_多元函數的條件極值和拉格朗日乘數法

、條件極值、拉格朗日乘數法1. 轉化為無條件極值在討論多元函數極值問題時,如果遇到除了在定義域中尋求駐點(可能的極值點)外,對自變量再無別的限制條件,我們稱這類問題為函數的無條件極值。如求的極值,就是無條件極值問題。然而在…

深度學習之 RPN(RegionProposal Network)- 區域候選網絡

anchor boxes基本概念與作用: feature map 上的一個點可以映射回輸入圖片上的一個點,以特征圖上這個點為中心,預先人為設定 k 個 boxes,這些 boxes 就稱為在這個點上生成的 k 個 anchor boxes(所有anchor boxes的中心點坐標是一樣…

h264的碼率控制 JVT-G012

開始看h264的碼率控制,很多地方都提到 G012,拿來做為參考比較,看來很有必要研究清楚。 偶這人,E文文檔不翻譯的話,看過就忘了,于是草草翻譯了下,因為不打算做B幀,也不準備在同一幀中…

Android RecyclerView嵌套EditView實時更新Item數據

一、場景(例如:購物車) 1、當我們需要以列表樣式管理某些數據時,可能需要列表項的某個字段可編輯 2、編輯Item上的某個字段后可能還要更新相關字段的值 二、可能遇到的問題 1、列表滑動導致輸入框中的數據錯位(或者焦點…

workbench拓撲優化教程_優化技術在水泵水力設計的應用(上篇)

文章來源:安世亞太官方訂閱號(搜索:Peraglobal)CFD技術在泵的內流數值模擬、研究泵內部流動規律和結構方面已廣泛應用,取得了很多成果。但是初步設計的產品如果通過CFD仿真得到的性能曲線不能滿足使用要求,…

深度學習之 TensorRT

1 簡介 TensorRT是一個高性能的深度學習推理(Inference)優化器,可以為深度學習應用提供低延遲、高吞吐率的部署推理。TensorRT可用于對超大規模數據中心、嵌入式平臺或自動駕駛平臺進行推理加速。TensorRT現已能支持TensorFlow、Caffe、Mxne…

H.264筆記

H.264標準寫得比較繁復,所以考慮在瀏覽完Whitepaper之后就開始研讀X264代碼。X264代碼風格還是比較清晰簡潔的。根據對標準得理解,Picture Order Count在Slice解碼的一開始就被提及:I0 B1 B2 P3 B4 B5 P6I0 P3 B1 B2 P6 B4 B5于是I0的POC是0&…

進制轉換中dbho是什么意思_什么是網段?二進制十進制如何互相轉換?看完這篇,你就全明白了...

之前的文章講了ip,子網掩碼,網關的關系,今天著重講一下網段。我們用傻瓜交換機通訊時,一個網段的設備才能互相通訊,怎么能判斷兩個ip是同一個網段呢?今天就簡單的說一下。(這篇文章用語音聽可以起到催眠作用…

【網絡流24題】星際轉移問題(最大流)

【網絡流24題】星際轉移問題(最大流) 題面 Cogs 題解 因為天數是未知的,所以我們要想辦法處理天數 可以選擇二分或者依次累加天數 因為數據范圍較小,使用二分可能反而復雜度會增高 所以使用不斷累加天數 那么,把所有的…

使用 gunicorn 部署flask項目

1、WSGI協議 Web框架致力于如何生成HTML代碼,而Web服務器用于處理和響應HTTP請求。Web框架和Web服務器之間的通信,需要一套雙方都遵守的接口協議。WSGI協議就是用來統一這兩者的接口的。 2、WSGI容器 常用的WSGI容器有Gunicorn和uWSGI,但G…

軟件需求與問題解決

(一) 小滿當上項目經理后不久,參與了一個大項目。當時市場簽下來的時候,公司里面是歡天喜地的。項目做了一年多。到了交付的時候,用戶卻很不滿意,當初說好的東西,好多都變了卦。用戶是上帝&…

flex 換主軸后子元素占滿_Chrome72 嵌套 flex 布局修改,你的網站可能會發生布局錯亂...

起源2019 年 1 月 29 日,Chrome72 正式版(72.0.3626.81)發布,本次發布帶來了一個改變,且沒有在更新日志中提及,該改變導致某些網站發生了布局錯亂。該改變主要針對的是嵌套的flex布局,下面我們一起看下是怎么回事。問題…

使用 Django + Wusgi + Nginx 部署 Django

如何在生產上部署Django? Django的部署可以有很多方式,采用 nginxuwsgi 的方式是其中比較常見的一種方式。 uwsgi介紹 uWSGI是一個Web服務器,它實現了WSGI協議、uwsgi、http等協議。Nginx中HttpUwsgiModule的作用是與uWSGI服務器進行交換。 WSGI / …

網絡學習網址

網絡之路博客 http://ccieh3c.com/ 轉載于:https://www.cnblogs.com/changha0/p/8179801.html

路由到另外一個頁面_Nextjs使用解讀一(項目搭建與路由系統)

文章說明:1. 之前想搭建個人博客,由于學習的是react技術棧,所以就到處搜羅資料學了nextjs,配合koa就把博客搭起來了。該系列文章基于我的學習筆記,重新整理了一遍,如果有錯誤之處,還請指正。2. …

微信獲取token -1000

最終翻看微信開發api找到需要去配置IP白名單。只需要配置訪問來源IP即可。 轉載于:https://www.cnblogs.com/yangjinqiang/p/8184663.html

產品技術和管理

為啥純粹為消費者傳遞體驗的活動可以價格不菲,幾為暴利?——談客戶體驗作為客戶價值提升之源 不論產品還是服務,如果能夠為消費者傳遞有益的體驗,其價值就可以在一般的產品服務之上得以體現;附加了體驗的產品&#xff…