我们小程序页面都需要确保登陆后,再用token进行数据请求,如何做到?
发布于 4 年前 作者 lixiao 6708 次浏览 来自 官方Issues

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

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

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

9 回复

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

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

import Taro from '[@tarojs](/user/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个请求。

请查看微信小程序登陆规范 九月份开始你这个强制登陆就审核不通过了

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

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

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

app.js

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

调用

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

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

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

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

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

回到顶部