從session原理出發解決微信小程序的登陸問題


聲明:本文為作者原創文章,轉載請注明出處 https://www.cnblogs.com/MaMaNongNong/p/9127416.html 

原理知識准備

   對於已經熟悉了session原理的同學來說,我們都清楚:在瀏覽器端我們會存儲一個sessionId,用它來作為憑證,在服務器端得到有關本次瀏覽器與服務器會話的所有信息,這些信息是儲存在服務器端的存儲空間中的,它完全可以用來判斷一個瀏覽器端的登錄狀態,因為它是由服務器端來掌控的,是安全的。

  那么瀏覽器端是用什么來存儲這個sessionId? 並且瀏覽器又是如何將sessionId傳回給服務器的呢?

  大體上是有兩種方法的:

    1、使用瀏覽器端實現的cookie功能,每次瀏覽器都會將服務器傳過來的cookie內容按鍵值對的方式放到瀏覽器的緩存中,然后下次請求同一個服務器時又會將cookie內容取出來送回服務器,當然其中就有存儲在cookie中的sessionId。

    2、使用URL重寫的方法,URL地址重寫是對客戶端不支持Cookie的解決方案。URL地址重寫的原理是將該用戶Session的id信息重寫 到URL地址中。服務器能夠解析重寫后的URL獲取Session的id。這樣即使客戶端不支持Cookie,也可以使用Session來記錄用戶狀態。

 

 

    

  不到迫不得已的地步,我是不會考慮第二種,也就是使用URL重寫的方法的。

 

  其實,實際的應用場景無非就是以下兩種,我們用病人看病的例子來理一理:

 

  第一種,醫生給病人看病,一天有幾百個病人,不可能把所有的病人的病情都記得清清楚楚,所以就需要一個病歷本,病人下次來看病的時候醫生就可以根據病人的病歷本上記錄的信息來得到病人的病情狀況。(這種情況對應的就是瀏覽器端只使用cookie與服務器進行交互的情況)

 

  第二種,有一些特殊的病人,他們是毒癮患者,正在接受戒毒的輔助治療,每個月需要到醫院領取少量的類似毒品的葯物來逐步減少毒品攝入量;醫院也給他一個病歷本,但是由於使用葯物的特殊性,為了防止某些不法分子偽造病歷本去領取違禁葯物,於是就給每個病歷本上使用GUID算法生成了一個獨一無二的病歷號,在醫生這里也有一個本子,上面記錄了所有特殊病人的病歷號,下次病人來拿違禁葯物的時候,醫生需要對照病人的病歷號來查詢是否存在這個病人和他需要領取葯品的具體量。這樣,就可以防止非法人員冒充和病人惡意更改葯品領取量的情況發生。(這種情況對應的就是通過sessionId來查詢出本次瀏覽器與服務器的會話信息的情況,病歷本上的病歷號就相當於sessionId)

 

   上面寫了這么多關於session的原理內容就是為了下面引出正題做准備的,所以到這里還不明白session原理的同學可以繞道去找一些關於session的文章研究研究,再回來接着往下看。

  推薦一篇大神的關於session原理的文章:

  https://www.cnblogs.com/linguoguo/p/5106618.html

 

問題提出

 

  下面展開正題,問題是這樣的:

  在開發微信小程序的過程中需要實現一個小程序登陸的功能,由於小程序中與服務器的交互大部分使用的都是HTTP通信,所以完全可以仿照之前開發B/S的那一套登陸體系,利用上面提到的sessionId的方式在服務器端進行登陸態的存儲,進行是否登錄的判斷。相對於以前的 服務器/瀏覽器 的開發模式,服務器/微信小程序 開發模式有一個初級開發者需要注意的點,就是:微信小程序是不會將HTTP報文頭中的COOKIE信息存入緩存中的,自然也就不會將COOKIE的內容傳回給服務器端,簡單的說就是 微信小程序端沒有幫你實現cookie機制

  

   所以,如果你想當然的就認為微信小程序已經幫你在背后實現了cookie機制,那么你就會像我一樣,踩入了一個大坑。
 
  下面是我的踩坑歷程,咱從坑中領悟: 
 
  
服務器端的一段程序(.net MVC 的 Action方法程序)
  
        public ActionResult SessionTest()
        {
            Session["TestValue"] = 1;

            return Json(new { message = "this is a test response" });
        }    

  

使用微信小程序的原生request方法寫的請求程序

 sendRequest:function(){

    wx.request({

        url:'http://localhost:51112/Test/SessionTest',
        method:'POST',
        success:function(res){

          console.log("進行了一次請求");

        },
        fail:function(){

          console.log("請求失敗");

        }
    });

  }

 

   過程就是用小程序的這段代碼運行,去請求服務器,服務器執行的就是上面展示的那段action方法的代碼。

   總共請求兩次,兩次請求的http報文頭如下:

  第一次請求:

  

 

 

  (請求報文頭):

   

 

  (應答報文頭):

 

 

  由於這是微信小程序第一次與服務器進行交互,所以並沒有攜帶任何cookie的內容,這是很正常的現象。等到服務器應答瀏覽器時,就給了瀏覽器一個sessionId,字段名為 ASP.NET_SessionId  值為  saqu0pv20q5jkd1q2dlmxcyg 。到這里我們如果認為微信小程序已經實現了cookie機制,那么下一次向同一個域名進行請求的時候,我們會在請求報文頭中看到會有一個cookie字段,里面會有上一次微信小程序從服務器那里得到的sessionId的值。

  然而。。。

  

 第二次請求:

 

  

   

       (請求報文頭):

   

 

  (應答報文頭):

    

 

   看到這里你就會發現它與你預想的完全不一樣了。。首先,請求報文頭中並沒有發現有上一次服務器給微信小程序端傳的sessionId;然后,服務器返回給小程序的報文頭中的 ASP.NET_SessionId  值變成了 cwugbbt0mmliha0ul4ccx4l2  並非原先的  saqu0pv20q5jkd1q2dlmxcyg 。

   發生的一切都指向一個原因,那就是 小程序並沒有實現cookie的機制導致小程序請求服務器的報文頭中並沒有攜帶sessionId,服務器拿不到sessionId,就會認為這是另外一個還沒有對服務器請求過的客戶端,就新生成了一個sessionId給微信小程序端,所以小程序端就拿到了不同於上次的sessionId。

 

   到現在,所有的現象以及現象背后的原因都解釋通了,那么接下來就是怎么解決問題。

 

解決方法與過程

      其實解決問題的方法很簡單,既然微信小程序端沒有實現cookie機制,那么就自己實現cookie機制唄。

   思路:cookie機制最簡單的功能無非就是將服務器返回的 應答報文中cookie部分找個地方存起來,以后再向服務器發出請求時就將存儲的cookie內容取出,填充到請求報文頭中。

   存到一個地方,存到哪呢?有兩個合適的地方:

    1、微信小程序的緩存。

      2、微信小程序的全局變量中。

   我選擇第二種,將cookie內容存到微信小程序的全局變量中去,下面是我自己封裝的一個自動攜帶cookie中的sessionId去請求的請求函數實現:

 

   在封裝之前,最好先去微信小程序的官網看一下   wx.request 函數的說明。點這里

 

//app.js
App({
  
  globalData: {
    cookie: '',      //供小程序存儲cookie數據使用
  }
})
 
         
//帶着sessionId進行請求,自動獲取服務端返回的sessionId存入全局變量中
function RequestBySessionId(requestParam){

  //三個默認參數的值
  var method = "GET";
  var dataType = "json";
  var responseType = "text";
  //用戶輸入了參數就替換,沒輸入就使用默認的
  if ("method" in requestParam)
  {
    method = requestParam.method;
  }
  if ("dataType" in requestParam) {
    dataType = requestParam.dataType;
  }
  if ("responseType" in requestParam) {
    responseType = requestParam.responseType;
  }

  var url = requestParam.url;
  var data = requestParam.data;
  var success = requestParam.success;
  var fail = requestParam.fail;
  var complete = requestParam.complete;

  var cookieStr = "";  //請求報文頭中cookie的字符串

  var Cookie = App.globalData.cookie;  //獲取全局變量中的cookie內容
  cookieStr = Cookie;

  var header = {};
  if ("header" in requestParam)
  {
    header = requestParam.header;
    header["Cookie"] = cookieStr;
  }
  else
  {
    header["Cookie"] = cookieStr;
  }

  wx.request({
    url: url,
    method: method,
    responseType: responseType,
    dataType: dataType,
    data: data,
    header: header,    //每次請求帶上sessionId
    success: function(res){

      //先將檢查服務器返回報文頭中有無sessionId,有則存到全局變量中
      var cookie = res.header["Set-Cookie"];
      if (undefined != cookie)
      {
        var sessionPos;
        if ((sessionPos = cookie.indexOf("ASP.NET_SessionId=")) != -1) {

          //每次請求成功都將sessionId存入全局變量
          App.globalData.cookie = cookie.substring(sessionPos, 42);
        }
      }
      //執行正常的操作
      success(res);
    },
    fail: fail,
    complete: complete,
  });
}

 

  經過了這一波封裝,就等於是有了微信小程序中請求的”神器“了,麻麻再也不用擔心我把sessionId搞丟了。

  

  下面咱就再一次使用封裝后的函數來進行請求發送試驗:

  

   改造后的微信小程序端請求代碼:

 

   var utils = require('../../utils/util.js'); //引用 util.js 文件

sendRequest:function(){ utils.RequestBySessionId({ url: 'http://localhost:51112/Test/SessionTest', method: 'POST', success: function (res) { console.log("進行了一次請求"); }, fail: function () { console.log("請求失敗"); } }); }

 

 

 

  

   同樣的過程:用小程序的這段代碼運行,去請求服務器,服務器執行的就是上面原先展示的那段action方法的代碼。

   總共請求兩次,兩次請求的http報文頭如下:

  第一次請求:

  

 

 

  (請求報文頭):

   

 

 

  (應答報文頭):

 

 

 

  看到這次服務器返回的 ASP.NET_SessionId  值為  dodngz2ahcznp4r3hrmavd1c

  然后,注意了。。。

  

 第二次請求:

 

  

   

       (請求報文頭):

   

 

   看到第二次請求報文頭中的cookie了嗎,里面就是 ASP.NET_SessionId= dodngz2ahcznp4r3hrmavd1c

   說明了,已經成功將sessionId帶上了。。。

 

  (應答報文頭):

    

 

  服務器返回的報文中已經沒有sessionId了,因為已經不需要了。。。

  

    以上就是我對微信小程序中自創cookie的解決方法,其實你會發現原理其實很簡單,但是如果你沒有深入過session的原理,你會很迷惑。

  所以,還是那句話:明白原理最重要,掌握了原理也就掌握了一切。。。

  晚安,同學們。

 

轉載請注明出處  https://www.cnblogs.com/MaMaNongNong/p/9127416.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM