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

来源:https://www.cnblogs.com/MaMaNongNong/archive/2018/06/08/9127416.html
-Advertisement-
Play Games

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


原理知識準備

   對於已經熟悉了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


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 本篇教大家如何用Python來實現QQ機器人,如有不足歡迎在評論方指出! 簡單介紹 安裝方法 可在 Python個版本下使用,用 pip 安裝: 使用方法 一、啟動 QQBot 二、操作 QQBot QQBot 啟動後,在另一個控制台視窗使用 qq 命令來操作 QQBot ,目前提供以下命令: li ...
  • 現有要求如下: 通過cmd的方式,求簡單表達式的值。 比如輸入 java Expression 3 + 4 得到的結果為:7 代碼: import java.text.DecimalFormat; public class Expression { public static void main(S ...
  • 本節主要內容:1. 初識⽂件操作2. 只讀(r, rb)3. 只寫(w, wb)4. 追加(a, ab)5. r+讀寫6. w+寫讀7. a+寫讀(追加寫讀)8. 其他操作⽅法9. ⽂件的修改以及另⼀種打開⽂件句柄的⽅式 主要內容:⼀. 初識⽂件操作使⽤python來讀寫⽂件是⾮常簡單的操作. 我們 ...
  • 一、常用字元串操作 upper(x)把字母變成大寫 lower(x)把字母變成小寫 split(str,num) 對字元串進行切割,返回一個列表:str-分隔符,預設為所有的空字元,包括空格,換行(\n),製表符(\t)等;num -- 分割次數 strip(chars ) 移除字元串頭尾指定的字元 ...
  • 有話要說: 這次準備講述後臺伺服器的搭建以及前臺訪問到數據的過程。 成果: 準備: 搭建伺服器: 用eclipse直接創建一個web工程,並將運行環境設置為Tomcat7 接著定義了四個類來實現了一個簡單的介面(通過servlet的方式),下麵來看看這四個類 NewsBean.java 該類是段子類 ...
  • 4、為何需要進行url去重? 運行爬蟲時,我們不需要一個網站被下載多次,這會導致cpu浪費和增加引擎負擔,所以我們需要在爬取的時候對url去重,另一方面:當我們大規模爬取數據時,當故障發生時,不需要進行url鏈接重跑(重跑會浪費資源、造成時間浪費) 5、如何確定去重強度? 這裡使用去重周期確定強度: ...
  • Brotli是一種全新的數據格式,可以提供比Zopfli高20-26%的壓縮比。據谷歌研究,Brotli壓縮速度同zlib的Deflate實現大致相同,而在Canterbury語料庫上的壓縮密度比LZMA和bzip2略大。 鏈接:Google開源Brotli壓縮演算法 微軟使用了一種基於谷歌提供的C代 ...
  • 1、訂閱序列using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Reactive;using System.Reactive.Linq;using System.... ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...