Une brève analyse de la façon d'implémenter la fonction de connexion dans les mini-programmes

青灯夜游
Libérer: 2021-12-06 10:13:11
avant
4279 Les gens l'ont consulté

Comment implémenter la fonction de connexion dans le mini programme ? Cet article vous présentera la bonne façon d'ouvrir la connexion au mini-programme. J'espère qu'il vous sera utile !

Une brève analyse de la façon d'implémenter la fonction de connexion dans les mini-programmes

Composant réseau du mini-programme

https://developers.weixin.qq.com/miniprogram/dev/api/network/request/wx.request.html

RequestTask Description

Méthode Description
RequestTask.abort() Abandonner la tâche de demande.
RequestTask.onHeadersReceived (rappel de fonction) Écoutez les événements d'en-tête de réponse HTTP. se produira avant l’événement d’achèvement de la demande.
RequestTask.offHeadersReceived(function callback) Annulez l'écoute des événements d'en-tête de réponse HTTP.
RequestTask.onChunkReceived(function callback) Écoutez l'événement Transfer-Encoding Chunk Reçu. Lancé lorsqu'un nouveau morceau est reçu.
RequestTask.offChunkReceived(function callback) Annulez l'écoute de l'événement Transfer-Encoding Chunk Receiver.

attribut wx.request(Object object)

Seuls les attributs les plus couramment utilisés sont répertoriés ici, veuillez consulter le lien pour tous les attributs.

Property Type Valeur par défaut Obligatoire Description
url string
Oui Adresse de l'interface du serveur développeur
data string /object/ArrayBuffer
Non Paramètres demandés
header Object
Non Définir l'en-tête demandé ne peut pas être défini dans l'en-tête. content-type 默认为 application/json
timeout number
Non Timeout en millisecondes
method string GET Non Méthode de requête HTTP
succès fonction
Non La fonction de rappel pour un appel d'interface réussi
échec fonction
Non La fonction de rappel pour un appel d'interface échoué
complet fonction
Non La fonction de rappel à la fin de l'appel de l'interface (sera exécutée que l'appel soit réussi ou échoué) même s'il s'agit d'une requête avortée !

Pour résumer : toutes les interfaces de mini-programmes ont essentiellement deux caractéristiques :

  • Les paramètres sont tous un objet. Facile à retenir et facile à développer.

  • ont tous la même méthode de traitement des résultats : ils ont tous trois attributs de rappel : succès, échec et complet.

Introduction à l'objet errMsg dans diverses situations d'exécution d'interface.

Propriété de rappel Objet errMsg
succès {errMsg:"request:ok"...}
fail {er rM sg:"requête:échec". . .} Dans certains systèmes, il y a un espace après cet échec, donc pour utiliser ce jugement, il est préférable d'utiliser des expressions régulières. Vous pouvez également utiliser la fonction indexOf pour juger si elle est supérieure à -1.
abort {errMsg:"request:fail abort"...}

Exemple de code

  let reqTask = wx.request({
      url: getApp().globalData.api,
      success(res) {
        if (res.errMsg === "request:ok") console.log("res", res);
      },
      fail(err) {
        // if(err.errMsg.indexOf('request:fail')>-1) console.log('err', err);
        if (/^request:fail/i.test(err.errMsg)) console.log("err", err);
      },
      complete(res) {
        console.log("resOrErr", res);
      },
    });
   const reqTaskOnHeadersReceived = (headers) => {
      reqTask.offHeadersReceived(reqTaskOnHeadersReceived);
      console.log("headers", headers);
      // 由于请求还未完全结束,所以我们没办法获得请求的状态码,但是我们可以通过返回的requestBody的长度来进行判断。
      // 两点说明:1. 两个~~可以把字符串数字快速转化为数字。
      // 2. 为什么取小于19,是由于后台返回没有权限的requestBody的时候Content-length为“18”,正常情况下是大于19的。所以具体多少得看一下具体情况。
      if (~~headers.header["Content-length"] < 19) reqTask.abort();
    };
    reqTask.onHeadersReceived(reqTaskOnHeadersReceived);
Copier après la connexion

Interface de connexion au mini programme

  • wx.getUserProfile (objet objet)

    Obtenir des informations sur l'utilisateur. La page génère un événement de clic (par exemple buttonbindtap 的回调中)后才可调用,每次请求都会弹出授权窗口,用户同意后返回 userInfo。该接口用于替换 wx.getUserInfo, veuillez consulter Instructions de réglage de l'interface d'informations utilisateur pour plus de détails.

  • wx.checkSession(Object object)

    Vérifiez si le statut de connexion a expiré. Le statut de connexion de l'utilisateur obtenu via l'interface wx.login a une certaine rapidité. Plus l'utilisateur n'a pas utilisé le mini-programme depuis longtemps, plus il est probable que le statut de connexion de l'utilisateur devienne invalide. Au contraire, si l'utilisateur a utilisé le mini-programme, la logique de synchronisation spécifique sera maintenue par WeChat et sera transparente pour les développeurs. Les développeurs n'auront qu'à appeler l'interface wx.checkSession pour vérifier si l'état de connexion actuel de l'utilisateur est valide

    Après l'expiration de l'état de connexion, le développeur peut appeler wx. .login pour obtenir un nouvel état de connexion utilisateur. Un appel réussi signifie que la clé de session actuelle n'a pas expiré, et un appel échoué signifie que la clé de session a expiré. Voir Connexion au mini-programme pour plus de détails. wx.login(Object object)

  • Appelez l'interface pour obtenir les informations sur l'état de connexion de l'utilisateur (code). L'identifiant unique du mini programme actuel (openid), l'identifiant unique du compte de la plateforme ouverte WeChat (unionid, si le le mini-programme actuel est lié au compte de la plateforme ouverte WeChat), et la clé de session (session_key) de cette connexion, etc. La communication de cryptage et de décryptage doit être complétée en s'appuyant sur la clé de session. Pour plus de détails, voir

    Connexion au mini-programme.

    implémentation du code de l'interface de connexion backend

Le backend utilise NodeJS, framework Web KOA version ^2.13, framework de routage @koa/router version ^10.1.1, requête de framework, version ^2.88. 2, jsonwebtoken est utilisé pour crypter et déchiffrer les informations du jeton, version ^8.5.1

// app.js
const Koa = require("koa");
const Router = require("@koa/router");
const WeixinAuth = require("./lib/koa2-weixin-auth");
const jsonwebtoken = require("jsonwebtoken");

const app = new Koa();
// 小程序机票信息
const miniProgramAppId = "*********";
const miniProgramAppSecret = "***********";
const weixinAuth = new WeixinAuth(miniProgramAppId, miniProgramAppSecret);

const JWT_SECRET = "JWTSECRET";
// 路由中间件需要安装@koa/router
// 开启一个带群组的路由
const router = new Router({
  prefix: "/user",
});
// 这是正规的登陆方法
// 添加一个参数,sessionKeyIsValid,代表sessionKey是否还有效
router.post("/weixin-login", async (ctx) => {
  let { code, userInfo, encryptedData, iv, sessionKeyIsValid } =
    ctx.request.body;
   // 解析openid
  const token = await weixinAuth.getAccessToken(code);
  userInfo.openid = token.data.openid;
  // 这里可以自己进行处理,比方说记录到数据库,处理token等
  let authorizationToken = jsonwebtoken.sign(
    { name: userInfo.nickName },
    JWT_SECRET,
    { expiresIn: "1d" }
  );
  Object.assign(userInfo, { authorizationToken });
  ctx.status = 200;
  ctx.body = {
    code: 200,
    msg: "ok",
    data: userInfo,
  };
});
Copier après la connexion
// lib/koa2-weixin-auth.js
const querystring = require("querystring");
const request = require("request");

const AccessToken = function (data) {
  if (!(this instanceof AccessToken)) {
    return new AccessToken(data);
  }
  this.data = data;
};

/*!
 * 检查AccessToken是否有效,检查规则为当前时间和过期时间进行对比
 *
 * Examples:
 * ```
 * token.isValid();
 * ```
 */
AccessToken.prototype.isValid = function () {
  return (
    !!this.data.session_key &&
    new Date().getTime() < this.data.create_at + this.data.expires_in * 1000
  );
};

/**
 * 根据appid和appsecret创建OAuth接口的构造函数
 * 如需跨进程跨机器进行操作,access token需要进行全局维护
 * 使用使用token的优先级是:
 *
 * 1. 使用当前缓存的token对象
 * 2. 调用开发传入的获取token的异步方法,获得token之后使用(并缓存它)。

 * Examples:
 * ```
 * var OAuth = require(&#39;oauth&#39;);
 * var api = new OAuth(&#39;appid&#39;, &#39;secret&#39;);
 * ```
 * @param {String} appid 在公众平台上申请得到的appid
 * @param {String} appsecret 在公众平台上申请得到的app secret
 */
const Auth = function (appid, appsecret) {
  this.appid = appid;
  this.appsecret = appsecret;
  this.store = {};

  this.getToken = function (openid) {
    return this.store[openid];
  };

  this.saveToken = function (openid, token) {
    this.store[openid] = token;
  };
};

/**
 * 获取授权页面的URL地址
 * @param {String} redirect 授权后要跳转的地址
 * @param {String} state 开发者可提供的数据
 * @param {String} scope 作用范围,值为snsapi_userinfo和snsapi_base,前者用于弹出,后者用于跳转
 */
Auth.prototype.getAuthorizeURL = function (redirect_uri, scope, state) {
  return new Promise((resolve, reject) => {
    const url = "https://open.weixin.qq.com/connect/oauth2/authorize";
    let info = {
      appid: this.appid,
      redirect_uri: redirect_uri,
      scope: scope || "snsapi_base",
      state: state || "",
      response_type: "code",
    };
    resolve(url + "?" + querystring.stringify(info) + "#wechat_redirect");
  });
};

/*!
 * 处理token,更新过期时间
 */
Auth.prototype.processToken = function (data) {
  data.create_at = new Date().getTime();
  // 存储token
  this.saveToken(data.openid, data);
  return AccessToken(data);
};

/**
 * 根据授权获取到的code,换取access token和openid
 * 获取openid之后,可以调用`wechat.API`来获取更多信息
 * @param {String} code 授权获取到的code
 */
Auth.prototype.getAccessToken = function (code) {
  return new Promise((resolve, reject) => {
    const url = "https://api.weixin.qq.com/sns/jscode2session";
    //由于此框架版本很久没有更新了,此处地址发生了变化,需要修改为以上地址,不然会出现
    //41008错误。这也是没有直接使用框架,引用本地使用的原因。
    // const url = "https://api.weixin.qq.com/sns/oauth2/access_token";
    const info = {
      appid: this.appid,
      secret: this.appsecret,
      js_code: code,
      grant_type: "authorization_code",
    };
    request.post(url, { form: info }, (err, res, body) => {
      if (err) {
        reject(err);
      } else {
        const data = JSON.parse(body);
        resolve(this.processToken(data));
      }
    });
  });
};

/**
 * 根据refresh token,刷新access token,调用getAccessToken后才有效
 * @param {String} refreshToken refreshToken
 */
Auth.prototype.refreshAccessToken = function (refreshToken) {
  return new Promise((resolve, reject) => {
    const url = "https://api.weixin.qq.com/sns/oauth2/refresh_token";
    var info = {
      appid: this.appid,
      grant_type: "refresh_token",
      refresh_token: refreshToken,
    };
    request.post(url, { form: info }, (err, res, body) => {
      if (err) {
        reject(err);
      } else {
        const data = JSON.parse(body);
        resolve(this.processToken(data));
      }
    });
  });
};

/**
 * 根据openid,获取用户信息。
 * 当access token无效时,自动通过refresh token获取新的access token。然后再获取用户信息
 * @param {Object|String} options 传入openid或者参见Options
 */
Auth.prototype.getUser = async function (openid) {
  const data = this.getToken(openid);
  console.log("getUser", data);
  if (!data) {
    var error = new Error(
      "No token for " + options.openid + ", please authorize first."
    );
    error.name = "NoOAuthTokenError";
    throw error;
  }
  const token = AccessToken(data);
  var accessToken;
  if (token.isValid()) {
    accessToken = token.data.session_key;
  } else {
    var newToken = await this.refreshAccessToken(token.data.refresh_token);
    accessToken = newToken.data.session_key;
  }
  console.log("accessToken", accessToken);
  return await this._getUser(openid, accessToken);
};

Auth.prototype._getUser = function (openid, accessToken, lang) {
  return new Promise((resolve, reject) => {
    const url = "https://api.weixin.qq.com/sns/userinfo";
    const info = {
      access_token: accessToken,
      openid: openid,
      lang: lang || "zh_CN",
    };
    request.post(url, { form: info }, (err, res, body) => {
      if (err) {
        reject(err);
      } else {
        resolve(JSON.parse(body));
      }
    });
  });
};

/**
 * 根据code,获取用户信息。
 * @param {String} code 授权获取到的code
 */
Auth.prototype.getUserByCode = async function (code) {
  const token = await this.getAccessToken(code);
  return await this.getUser(token.data.openid);
};

module.exports = Auth;
Copier après la connexion

Implémentation du code de connexion du mini-terminal

<!--pages/index.wxml-->
<view class="page-section">
    <text class="page-section__title">微信登录</text>
    <view class="btn-area">
        <button  bindtap="getUserProfile" type="primary">登录</button>
    </view>
</view>
Copier après la connexion
// pages/index.js
Page({
  /**
   * 页面的初始数据
   */
  data: {},
  // 正确的登录方式
  getUserProfile() {
    // 推荐使用wx.getUserProfile获取用户信息,开发者每次通过该接口获取用户个人信息均需用户确认
    // 开发者妥善保管用户快速填写的头像昵称,避免重复弹窗
    wx.getUserProfile({
      desc: "用于完善会员资料", // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
      success: (res) => {
        let { userInfo, encryptedData, iv } = res;
        const requestLoginApi = (code) => {
          // 发起网络请求
          wx.request({
            url: "http://localhost:3000/user/weixin-login",
            method: "POST",
            header: {
              "content-type": "application/json",
            },
            data: {
              code,
              userInfo,
              encryptedData,
              iv,
            },
            success(res) {
              console.log("请求成功", res.data);
              let token = res.data.data.authorizationToken;
              wx.setStorageSync("token", token);
              onUserLogin(token);
              console.log("authorization", token);
            },
            fail(err) {
              console.log("请求异常", err);
            },
          });
        };
        const onUserLogin = (token) => {
          getApp().globalData.token = token;
          wx.showToast({
            title: "登录成功了",
          });
        };
        //必须进行session是否过期检查,不然会出现第一次点击登录,服务器报Illegal Buffer
        //的错误,但是第二次点击登录正常。
        wx.checkSession({
          success: (res) => {
            // session_key 未过期,并且在本生命周期一直有效
            console.log("在登陆中");
            let token = wx.getStorageSync("token");
            if (token) onUserLogin(token);
          },
          fail: (res) => {
            // session_key已经失效,需要重新执行登录流程
            wx.login({
              success(res0) {
                if (res0.code) {
                  requestLoginApi(res0.code);
                } else {
                  console.log("登录失败!" + res0.errMsg);
                }
              },
            });
          },
        });
      },
    });
  },
});
Copier après la connexion

Quelles optimisations peuvent être effectuées pour le code de connexion

Pour ? un logiciel, au niveau du code, vous devez poursuivre les aspects les plus élémentaires (bien plus que ceux-ci, mais faisons-les d'abord)) : Maintenabilité

La soi-disant "maintenance" n'est rien de plus qu'un travail tel comme la modification des bogues, la modification de l'ancien code et l'ajout de nouveau code. Le soi-disant « code est facile à maintenir » signifie que le code peut être modifié ou ajouté rapidement sans détruire la conception du code d'origine ni introduire de nouveaux bogues. le code n'est pas facile à maintenir" signifie que modifier ou ajouter du code nécessite un risque énorme d'introduire de nouveaux bugs, et cela prend beaucoup de temps

  • Lisibilité

    Le gourou de la conception de logiciels, Martin Fowler, a dit un jour : "N'importe quel imbécile peut écrire un code qu'un ordinateur peut comprendre. Les bons programmeurs écrivent du code que les humains peuvent comprendre. » Traduit en chinois : « N'importe quel imbécile peut écrire du code qu'un ordinateur peut comprendre. Les bons programmeurs peuvent écrire du code que les humains peuvent comprendre. "Il existe même une certification spéciale au sein de Google appelée Lisibilité. Seuls les ingénieurs qui ont obtenu cette certification sont qualifiés pour approuver les soumissions de code d'autres personnes lors de la révision du code. On peut voir à quel point la lisibilité du code est importante. Après tout, le code est lu. Le nombre de fois dépasse de loin le nombre de fois où il est écrit et exécuté. Nous devons vérifier si le code est conforme aux normes de codage, si le nom est significatif, si les commentaires sont détaillés, si la longueur de la fonction est appropriée, si la division des modules est claire, s'il répond à une cohésion élevée et à un faible couplage, etc.

  • Extensibilité (extensibilité)

    L'extensibilité est également un critère très important pour évaluer la qualité du code. Le code réserve certains points d'extension de fonction. insérez un nouveau code de fonction dans les points d'extension sans aucun besoin de faire de grands efforts pour ajouter une fonctionnalité et modifier beaucoup de code original

  • Réutilisabilité

    .

    代码的可复用性可以简单地理解为,尽量减少重复代码的编写,复用已有的代码。

那么接下来就来优化一下代码吧:

模块化

可以把登录的代码模块化,代码如下:

// lib/login.js
function loginWithCallback(cb) {
  // 推荐使用wx.getUserProfile获取用户信息,开发者每次通过该接口获取用户个人信息均需用户确认
  // 开发者妥善保管用户快速填写的头像昵称,避免重复弹窗
  wx.getUserProfile({
    desc: "用于完善会员资料", // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
    success: (res) => {
      let { userInfo, encryptedData, iv } = res;
      const requestLoginApi = (code) => {
        // 发起网络请求
        wx.request({
          url: "http://localhost:3000/user/weixin-login",
          method: "POST",
          header: {
            "content-type": "application/json",
          },
          data: {
            code,
            userInfo,
            encryptedData,
            iv,
          },
          success(res) {
            console.log("请求成功", res.data);
            let token = res.data.data.authorizationToken;
            wx.setStorageSync("token", token);
            onUserLogin(token);
            console.log("authorization", token);
          },
          fail(err) {
            console.log("请求异常", err);
          },
        });
      };

      const onUserLogin = (token) => {
        getApp().globalData.token = token;
        wx.showToast({
          title: "登录成功了",
        });
        if (cb && typeof cb == "function") cb(token);
      };
      wx.checkSession({
        success: (res) => {
          // session_key 未过期,并且在本生命周期一直有效
          console.log("在登陆中");
          let token = wx.getStorageSync("token");
          if (token) onUserLogin(token);
        },
        fail: (res) => {
          // session_key已经失效,需要重新执行登录流程
          wx.login({
            success(res0) {
              if (res0.code) {
                requestLoginApi(res0.code);
              } else {
                console.log("登录失败!" + res0.errMsg);
              }
            },
          });
        },
      });
    },
  });
}

export default loginWithCallback;
Copier après la connexion

Promise化

回调地狱问题,不利于代码的阅读,所以接下来我们基于Promise进行代码优化。有了 Promise 对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise 对象提供统一的接口,使得控制异步操作更加容易。

Promise的几个方法简介

Nom de la méthodeDescription
Promise.prototype.thenLa méthode renvoie un nouvel objet Promise, il peut donc être écrit de manière chaînée. Cette conception permet de réécrire facilement les opérations asynchrones imbriquées, du « développement horizontal » des fonctions de rappel au « développement descendant ».
Promise.prototype.catch est un alias de Promise.prototype.then(null, rejet), utilisé pour spécifier la fonction de rappel lorsqu'une erreur se produit. Les objets Errors on Promise ont une nature de « bulle » et seront propagés vers l’arrière jusqu’à ce qu’ils soient détectés. Autrement dit, l’erreur sera toujours détectée par la prochaine instruction catch. La méthode
Promise.prototype.finally renvoie une PromisePromise。在promise结束时,无论结果是fulfilled或者是rejected,都会执行指定的回调函数。这为在Promise是否成功完成后都需要执行的代码提供了一种方式。
Promise.all这避免了同样的语句需要在then()catch()中各写一次的情况。Promise.all 方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。Promise.all 方法接受一个数组作为参数,var p = Promise.all([p1,p2,p3]);p1、p2、p3 都是 Promise 对象的实例。(Promise.all 方法的参数不一定是数组,但是必须具有 iterator 接口,且返回的每个成员都是 Promise 实例。)p 的状态由 p1、p2、p3 决定,分成两种情况。 (1)只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。 (2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。
Promise.racePromise.race 方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。var p = Promise.race([p1,p2,p3]);上面代码中,只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的Promise实例的返回值,就传递给p的返回值。
Promise.any接收一个Promise可迭代对象,只要其中的一个 promise 成功,就返回那个已经成功的 promise 。所有子实例都处于rejected状态,总的promise才处于rejected状态。
Promise.allSettled返回一个在所有给定的promise都已经fulfilledrejected后的promise,并带有一个对象数组,每个对象表示对应的promise结果。相比之下,Promise.all() 更适合彼此相互依赖或者在其中任何一个reject. À la fin de la promesse, que le résultat soit rempli ou rejeté, la fonction de rappel spécifiée sera exécutée. Cela fournit un moyen pour le code qui doit être exécuté, que la Promesse se termine avec succès ou non.
Promise.all🎜🎜🎜Cela évite la situation où la même instruction doit être écrite une fois dans 🎜then()🎜 et 🎜catch()🎜. La méthode Promise.all est utilisée pour envelopper plusieurs instances Promise dans une nouvelle instance Promise. La méthode Promise.all accepte un tableau comme paramètre, var p = Promise.all([p1,p2,p3]);p1, p2, p3 sont toutes des instances de l'objet Promise. (Les paramètres de la méthode Promise.all ne sont pas nécessairement des tableaux, mais ils doivent avoir une interface itérateur et chaque membre renvoyé est une instance Promise.) L'état de p est déterminé par p1, p2 et p3 et est divisé en deux situations. (1) Ce n'est que lorsque les statuts de p1, p2 et p3 seront tous remplis que le statut de p sera rempli. À ce moment-là, les valeurs de retour de p1, p2 et p3 forment un tableau et sont transmises au. fonction de rappel de p. (2) Tant que l'un des p1, p2 et p3 est rejeté, le statut de p devient rejeté. À ce moment, la valeur de retour de la première instance rejetée sera transmise à la fonction de rappel de p. 🎜🎜🎜🎜 Promise.race🎜🎜🎜La méthode Promise.race encapsule également plusieurs instances Promise dans une nouvelle instance Promise. var p = Promise.race([p1,p2,p3]);Dans le code ci-dessus, tant qu'une instance parmi p1, p2 et p3 change d'abord l'état, l'état de p sera changer en conséquence. La valeur de retour de l'instance Promise qui a changé en premier est transmise à la valeur de retour de p. 🎜🎜🎜🎜 Promise.any🎜🎜🎜 reçoit un objet itérable Promise, et tant que l'une des promesses réussit, la promesse réussie sera renvoyée. Toutes les sous-instances sont à l'état rejeté et la promesse totale est à l'état rejeté. 🎜🎜🎜🎜 Promise.allSettled🎜🎜🎜 renvoie une promesse une fois que toutes les promesses données ont été réalisées ou rejetées, avec un tableau d'objets, chaque objet représentant le résultat de la promesse correspondant. En revanche, Promise.all() est plus adapté aux dépendances les unes des autres ou se termine immédiatement lorsque l'une d'elles rejette. 🎜🎜🎜🎜

小程序API接口Promise化并且把需要登录的调用接口模块化

1、安装插件。请先查看npm支持文档。

npm install --save miniprogram-api-promise
Copier après la connexion

2、在微信开发者工具右方详情中勾选使用npm模块,并在菜单栏工具中点击构建npm。

3、初始化代码。

// app.js
import {promisifyAll} from &#39;miniprogram-api-promise&#39;
import login from "../lib/login";
const wxp ={}
promisifyAll(wx,wxp)
// 需要token的请求统一处理登录和设置header,并且处理错误信息
wxp.requestNeedLogin = async function (args) {
  let token = wx.getStorageSync("token");
  if (!token) {
    token = await loginWithPromise();
  }
  if (!args.header) args.header = {};
  args.header["Authorization"] = `Bearer ${token}`;
  return wxp.request(args).catch(console.error);
};
// app.js
App({
  wxp:wxp,
});
Copier après la connexion

4、改写login.js代码

// lib/login.js
function login() {
  return new Promise((resolve, reject) => {
    // 推荐使用wx.getUserProfile获取用户信息,开发者每次通过该接口获取用户个人信息均需用户确认
    // 开发者妥善保管用户快速填写的头像昵称,避免重复弹窗
    wx.getUserProfile({
      desc: "用于完善会员资料", // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
       success:async (res0) => {
        let {
          userInfo,
          encryptedData,
          iv
        } = res0;
        const app = getApp();
        try {
          app.wxp.checkSession();
        } catch (err) {
          reject(err);
        }
        let token = wx.getStorageSync("token");
        if (!token) {
          let res1 = await app.wxp.login().catch(err => reject(err));
          let code = res1.code;
          let res = await app.wxp.request({
            url: "http://localhost:3000/user/weixin-login",
            method: "POST",
            header: {
              "content-type": "application/json",
            },
            data: {
              code,
              userInfo,
              encryptedData,
              iv,
            }
          }).catch(err => reject(err));
          token = res.data.data.authorizationToken;
          wx.setStorageSync("token", token);
          app.globalData.token = token;
          wx.showToast({
            title: "登录成功了",
          });
          resolve(token);
        }
      },
    });
  })
}

export default login;
Copier après la connexion

5、调用代码

<view class="container page-head">
  <text class="page-section__title">需要登录的请求调用</text>
  <view class="btn-area">
    <button bindtap="request1" type="primary">请求1</button>
    <button bindtap="request2" type="primary">请求2</button>
  </view>
</view>
Copier après la connexion
// pages/index.js
Page({
  /**
   * 页面的初始数据
   */
  data: {},
  request1() {
    getApp().wxp.requestNeedLogin({
        url: "http://localhost:3000/user/home?name=andying",
      }).then(console.log)
  },
  request2() {
    getApp().wxp.requestNeedLogin({
        url: "http://localhost:3000/user/home?name=eva",
      }).then(console.log)
  },
});
Copier après la connexion

【相关学习推荐:小程序开发教程

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:juejin.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal