マイクロ信ウィジェットインタフェース認証要求非同期問題

15328 ワード

マイクロ信ウィジェットインタフェース認証非同期問題
  • 前言
  • と一般インタフェースの認証の違い
  • ネット上のいくつかの方法の問題
  • ソリューション
  • まとめ
  • 前言
    この間、新しいウィジェットを作り始めました.いくつかの理由で、ウィジェットに入るとwxが必要です.loginはcodeを持ってバックエンドのログインインタフェースを調整してtokenを持って、その後ほとんどのインタフェースはこのtokenをパラメータとして要求する必要があります.これはインタフェースの認証に似ています.最初は私も確かにインタフェースの認証のようにしましたが、その中で多くの問題を発見しました.
    一般インタフェースとの認証の違い
    通常のインタフェース認証は、ユーザーが自主的にトリガーするログインプロセスがありますが、ウィジェット内のログインは、ウィジェットメカニズムの問題で、ウィジェットに入るとwxを通過することができます.loginがユーザーを識別するのは、ユーザーが自主的にトリガーする必要はありません.この違いは大きな違いです.tokenを必要とするインタフェースは、ログインインタフェースの呼び出しが完了した後に要求を開始しなければなりません.そうしないと、tokenはもらえません.一般的にtokenはstorageに保存されますが、ユーザーが初めてウィジェットに入ったときに問題があります.
    ネット上のいくつかの方法の問題
    ネット上で多くの方法を探しました.多くの解決策はappです.jsにはpromiseログインメソッドが書かれており、ページで呼び出され、コールバックでtokenが必要なリクエストメソッドを呼び出し続けます.これで問題を解決できますが、かなり面倒で、各ページにloginのリクエストが1つあり、コンポーネントを分けるときにリクエストをコンポーネントに置くことができません.ページの認証が必要なインタフェースはすべてページのloginコールバックに置かなければなりません.これは、コンポーネントの中でもtokenが必要なインタフェースリクエストをすると、ページのloginと重なるためです.1つのページに2回のログインインタフェースが要求されました.もう一つの方法は、自分でリクエストブロックを作って、リクエストブロックの中でtokenがあるかどうかを判断し、ない場合はloginを呼び出して取りに行きます.この方法では,ページの要求を1つのキューに並べなければならず,tokenを必要とするいくつかのインタフェースを同時に要求させることはできず,いったんいくつかのインタフェースが同時に要求されると,最初に入ったときに同時にいくつかのloginインタフェースをトリガーしてtokenを取りに行き,多くの不要な要求をもたらす.
    ソリューション
    ネット上のいくつかの方法はやはり頼りにならないので、自分で書くしかありません.最初の考えはやはりインタフェースのブロックの中でして、いわゆるインタフェースのブロックは実は自分で微信の方法によって1つのプロジェクトの共通の要求方法をカプセル化して、カプセル化の方法の中でブロックします.普通のほとんどのプロジェクトはこのようにして、axiosの要求ブロックパッケージに似ていて、本人のプロジェクトで使うtaroフレームワーク(ゴミですが、使わないほうがいいです)、taroフレームワークで持っている要求方法自体がpromiseにパッケージされているので使いやすいです.普通の小さなプログラムはまず要求方法をpromiseパッケージしなければなりません.私の方法は、tokenが必要なときにloginを要求することです.このlogin要求が進行中の場合、他のtokenが必要なインタフェースをブロックし、最初のlogin要求が完了してから要求するようにします.最初のloginリクエストが完了したらstorageを保存し、後のリクエストはそのままstorageに持って行けます.要求ブロックパッケージ
    // request.js
    import merge from 'merge'
    import { requestOptions } from './options'
    import { request as taroRequest } from '@tarojs/taro'
    
    /**
    *       
    * @param {Object} options   https://nervjs.github.io/taro/docs/apis/network/request/request.html#docsNav
    */
    export default async function request(options) {
    //  merge    options
    options = merge.recursive(true, requestOptions, options)
    //     token,         
    if (options.token) {
      options.token = Taro.getStorage('token')
    }
    //        
    options = await options.before(options)
    
    return taroRequest(options).then(res => {
      //        
      return res
    })
      .catch(() => {
        return {
          data: {
          //        
            error_code: 9999,
            error_message: '      ,   '
          }
        }
      })
    }
    

    optionsパッケージ、主にbefore関数
    const TIMEOUT = 20000
    import Taro from '@tarojs/taro'
    let flag = 0  //              
    let resolveList = []  //           optioons
    export const requestOptions = {
      url: '',
      method: 'POST',
      data: {},
      header: { 'content-type': 'application/x-www-form-urlencoded' },
      timeout: TIMEOUT,
      enableCache: false,
      token:true,  //     token
      before: async (options) => {
        return new Promise(async (resolve) => {
          //   token        
          if (options.token && !options.data.token) {
            if (flag) {
                //          false      
              flag = false
              //     
              const loginRes = await Taro.login()
              //         
              const { data } = await serve_login({ code: loginRes.code })
              //      ,             
              if (data.error_code == 0) {
                  //      token     token
                options.data.token = data.token
                //     ,               token
                Taro.setStorage('token',data.token)
                //       options        ,    
                resolve(options)
                //                 options        ,    
                resolveList.map(arr => {
                  arr.call({}, data.token)
                })
              } else {
                  //            
                Taro.showToast({
                  title: data.error_message,
                  icon: "none"
                })
                resolve(options)
              }
            } else {
              //             resolve      ,          ,            resolve
              resolveList.push((token) => {
                options.data.token = token
                resolve(options)
              })
            }
          } else {
            resolve(options)
          }
        })
      }
    }
    

    before関数の中で分かりにくいのは、自分がそう書いたとき、最初はtokenが必要だがtokenがないリクエストがresolveListに収められる可能性があるかどうか考えていたが、最初のログイン操作が完了したため、optionsパラメータresolveをブロッキングに渡さなかったことだ.しかし、もう一度よく考えてみると、この可能性はないはずです.最初のログインが完了すると、キャッシュにtokenがあり、storageからtokenを取得しようとするとtokenがもらえ、optionsに命中しないからです.token && !options.data.tokenではなく、すでにtokenがあるoptionsを直接ブロックに返し、要求を直接実行します.
    まとめ
    総じて言えば、今のところこの方法は私の需要の痛みを解決することができて、使ってもまだ何の問題も発見していませんが、私もブロックの中で要求をブロックするこのようなやり方がおかしいかどうか、あるいはどんな弊害があるかを考えています.もっと良い方法があるかもしれません.私はまだ知らないので、後で発見したときに記録して更新します.