從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
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...