收藏
回答

我们小程序页面都需要确保登陆后,再用token进行数据请求,如何做到?

有个问题困扰好久,我们小程序页面都需要确保登陆后,再用token进行数据请求。

如果将登陆写在在app.js的onLaunch,不能确保在页面onload的数据请求之前。因为,数据请求本来就是一个异步操作。

有没有更好的全局设置方法?

回答关注问题邀请回答
收藏

8 个回答

  • 张明明
    张明明
    2019-11-22

    写在request请求里吧,发起请求前从storage里拿token,如果没有拿到就调用登录接获取token,获取到token再继续发请求。相当于封装了请求预处理的统一拦截层,至于异步改同步的写法可以搜一下 async await,很方便使用

    2019-11-22
    有用 1
    回复 5
    • 三宏
      三宏
      2019-11-22
      一开页面多个接口异步同时在请求怎么办?后端怎么加锁?
      2019-11-22
      回复
    • 张明明
      张明明
      2019-11-22回复三宏
      那就多次请求呗,token在一段时间比如一个月时间里都不会变得,反正这种情况只有在用户第一次使用小程序才会出现,其他时间token写在storage里读取,能对系统造成多大阻塞呢?
      2019-11-22
      回复
    • 张明明
      张明明
      2019-11-22回复三宏
      另外还可以自己造一个生命周期函数挂在page对象上,当获取到了token,就触发这个生命周期函数,你的所有请求都挂在这个函数里面,就保证请求前一定有token的。
      2019-11-22
      回复
    • 张明明
      张明明
      2019-11-22回复张明明
      把请求token的网络请求封装为一个单独的函数,在其他request需要获取token的时候添加订阅,当token的网络请求返回数据时,发布给订阅者,这样就只需要提交一次token的网络请求
      2019-11-22
      回复
    • Api调用师
      Api调用师
      2022-01-10回复三宏
      试试新出炉的库,完美解决此问题,用完真香定律https://developers.weixin.qq.com/community/develop/article/doc/00002ac57208f0e7335d111f156013
      2022-01-10
      1
      回复
  • 哈士猪
    哈士猪
    2020-01-13

    这个问题其实在小程序生成的的默认模板中就有实例代码

    2020-01-13
    有用
    回复
  • 大师哥
    大师哥
    2019-09-16

    楼主解决了嘛?我之前是封装了请求他,判断是否登陆,登陆了继续请求接口未登录跳转到登陆页面。登陆成功返回页面。

    现在微信新规禁止强制登陆了。想请教一下你那面如何解决的?

    2019-09-16
    有用
    回复 1
    • 三宏
      三宏
      2019-09-18
      每个页面单独判断的,你也可以参照楼上的做法。他们那样是可行的
      2019-09-18
      回复
  • 被风吹散的雪
    被风吹散的雪
    2019-09-11

    登录不要写在app.js中,登录一定要写在单独封装的request里面。

    import Taro from '@tarojs/taro'
    import dva from '../dva'
    import { getStorageSyncLoginResult } from './index'
    import action from './action'
    import config from '../config'

    const makeOptions = (url, options) => {
    const defaultoptions = {
    url: undefined,
    method: 'GET',
    qs: undefined,
    body: undefined,
    headers: undefined,
    type: 'json',
    contentType: 'application/json',
    crossOrigin: true,
    credentials: undefined,
    customToken: false,
    showFailMsg: true,
    async: false,
    }

    let thisoptions = {}
    if (!options) {
    thisoptions = { url }
    } else {
    thisoptions = options
    if (url) {
    thisoptions.url = url
    }
    }
    thisoptions = Object.assign({}, defaultoptions, thisoptions, { qs: { ...thisoptions.qs, appId: config.appId } })

    return thisoptions
    }

    const addQs = (url, qs) => {
    let queryString = ''
     let newUrl = url
    if (qs && typeof qs === 'object') {
    /* eslint no-restricted-syntax: 0 */
       for (const k of Object.keys(qs)) {
    queryString += `&${k}=${qs[k]}`
       }
    if (queryString.length > 0) {
    if (url.split('?').length < 2) {
    queryString = queryString.substring(1)
    } else if (url.split('?')[1].length === 0) {
    queryString = queryString.substring(1)
    }
    }

    if (url.indexOf('?') === -1) {
    newUrl = `${url}?${queryString}`
       } else {
    newUrl = `${url}${queryString}`
       }
    }

    return newUrl
    }

    let token

    // invalidTryTimes 失效重试次数

    const request = (url, options, invalidTryTimes = 0) => {
    const opts = makeOptions(url, options)
    const { method, body, headers, qs, type, contentType } = opts

     let requestUrl = opts.url
     if (qs) requestUrl = addQs(requestUrl, qs)

    let header = headers
     if ((!headers || !headers['content-type']) && contentType) {
    header = Object.assign({}, headers, { 'content-type': contentType })
    }
    if (opts.customToken) {
    if (!token) {
    const res = getStorageSyncLoginResult()
    token = res && res.token
       }
    header = {
    ...header,
    'X-Custom-Token': token,
    }
    }

    const baseParam = {
    url: requestUrl,
    method,
    data: body,
    header,
    dataType: type,
    credentials: 'include',
    }

    return new Promise((resolve, reject) => {
    Taro.request(baseParam)
    .then(res => {
    let { statusCode, data } = res
    if (
    statusCode < 200 ||
    statusCode >= 300 ||
    (data.code !== 0 && (data.code < 200 || data.code >= 300))
    ) {
    let errors = {
    error: -1,
    request: url,
    errorMessage: '系统异常,请查看response',
    res,
    }
    if (data && typeof data === 'object') {
    errors = Object.assign({}, errors, data)
    }
    if (data.code === 401 && invalidTryTimes < 3 && !opts.async) {

    invalidTryTimes++

    // 如果接口返回失败后重新登录

                dva

                    .getDispatch()(action('user/login'))
    .then(_ => {

    token = null

    // 登录成功后清除token,重新发起请求

                     resolve(request(url, options, invalidTryTimes))
    })
    .catch(e => {
    reject(e)
    })
              } else {
    console.log('request error ===>', errors)
    reject(errors)
    }
    } else {
    resolve(data)
    }
    })
    .catch(err => {
    console.log('request error ===>', err)
    reject({
    error: -1,
    message: '系统异常,请查看response',
    err,
    request: requestUrl,
    })
    })
    })
    }

    export default request



    另外如果页面一开始有n个请求同时需要发出,那么需要一个checklogin的接口检测登录状态或者第一个请求完成后再发出后面n-1个请求。

    2019-09-11
    有用
    回复 11
    • 三宏
      三宏
      2019-09-11
      首先非常感谢!我们没有用taro,你的思路是把请求单封下,然后页面里面调用么?
      2019-09-11
      回复
    • 被风吹散的雪
      被风吹散的雪
      2019-09-12回复三宏
      用不同taro都一样,所有请求拦截,如果接口返回未登录,就去登录,登录完成后再次发出登录前的请求就可以了。
      2019-09-12
      回复
    • 被风吹散的雪
      被风吹散的雪
      2019-09-12
      不用程序程序一启动就去登录,而是看后端接口返回需不需要登录,需要的时候再去登录,登录完成后重新发起之前的请求就可以。获取用户信息可以在程序启动的时候再去获取,获取失败不用理会,也不用去登录。因为其他请求一旦需要登录,自然回去登录,并且登录完成后再去异步的获取用户信息就可以了。
      2019-09-12
      回复
    • 被风吹散的雪
      被风吹散的雪
      2019-09-12

      具体看代码,

      dva.getDispatch()(action('user/login'))
                      .then(_ => {
      token = null
       
      // 登录成功后清除token,重新发起请求
       
                        resolve(request(url, options, invalidTryTimes))
                      })
                      .catch(e => {
                        reject(e)
                      })

      这里是登录的逻辑,user/login里面就是登录,登录同样调用的这个request,登录完成后异步获取用户信息,然后resolve返回重新请求后的数据。

      2019-09-12
      1
      回复
    • 三宏
      三宏
      2019-09-12回复被风吹散的雪
      感谢!但我有个问题在于,我们如果没有登陆,就等于是一个注册。比如首页,一进来,多个接口异步同时需要登陆,这样等于约等于几乎都在同一时间在给后端进行注册请求。这个锁,不管是前端还是都没想到好点的办法解决
      2019-09-12
      回复
    查看更多(6)
  • 老张
    老张
    2019-08-22

    你的问题其实不是什么token的问题,而是异步的问题吧?那就参考我的这篇的思路,思路:把openid换成token。

    https://developers.weixin.qq.com/community/develop/doc/0008089ec2c6200b81e76e6ac56804

    2019-08-22
    有用
    回复 7
    • 三宏
      三宏
      2019-08-22
      我看了你的代码,意思也是每个页面都要去校对id对吧?问题就是几十个页面,都去校对,非常麻烦
      2019-08-22
      回复
    • 老张
      老张
      2019-08-22回复三宏
      感觉我的文章得不出你这样的结论。
      2019-08-22
      回复
    • 三宏
      三宏
      2019-08-22回复老张
      不是在任何页面的onLoad去调用getApp().getOpenId()么?
      2019-08-22
      回复
    • 老张
      老张
      2019-08-22回复三宏
      不需要openid的页面不用;需要的,你就不得不用。
      2019-08-22
      回复
    • 三宏
      三宏
      2019-08-22回复老张
      唉,问题就是这个。我们几十个界面。基本上都需要
      2019-08-22
      回复
    查看更多(2)
  • 九歌^
    九歌^
    2019-08-21

    = =为啥有这种操作。如果所有页面 都是需要强登录的 ,默认给用户展示一个落地页面。页面有授权按钮。点击后授权手机号。注册并返回用户的token等信息。

    2019-08-21
    有用
    回复 1
    • 三宏
      三宏
      2019-08-21
      不需要手机号码。只需要通过id拿到token就行。有用户交互显示模块,比如显示是否点赞,是否收藏的状态
      2019-08-21
      回复
  • 就在那里
    就在那里
    2019-08-15

    app.js

    wxlogin(){
      return new Promise(function (resolve, reject) {
        //登录请求...
       resolve(res);
       reject(err);
     }
    }

    调用

    app.wxlogin().then(res=>{}).catch(err=>{})


    2019-08-15
    有用
    回复 22
    • 三宏
      三宏
      2019-08-15
      这样写,我不能保证各个页面里面的请求接口在这个之后呀
      2019-08-15
      回复
    • 三宏
      三宏
      2019-08-15
      因为,app.js里面去后端通过id拿到token。这个异步操作是否完成,不能在页面里面获取
      2019-08-15
      回复
    • 就在那里
      就在那里
      2019-08-16回复三宏
      你请求之后把数据放到全局里,其他页面请求前先校验有没有数据咯
      2019-08-16
      回复
    • 三宏
      三宏
      2019-08-19回复就在那里
      问题是token请求和其它页面的请求不一定谁先执行
      2019-08-19
      回复
    • 就在那里
      就在那里
      2019-08-19回复三宏
      你其他请求先校验全局里面有没有token,没有就调用登录方法,拿到数据后再请求
      2019-08-19
      回复
    查看更多(17)
  • 一花
    一花
    2019-08-15

    写一个分离出来的登录页面,确认拿到token后跳转


    2019-08-15
    有用
    回复 2
    • 三宏
      三宏
      2019-08-15
      如果这样,用户直接分享的怎么办?
      2019-08-15
      回复
    • 张明明
      张明明
      2019-11-22回复三宏
      用户直接分享一样的啊,打开分享页面进来要接口请求啊,你把小程序的所有接口请求封装一下统一处理,不要到处wx.request,这样所以请求都会先获取token再发请求啊
      2019-11-22
      回复
登录 后发表内容
问题标签