【GoWeb開發實戰】Cookie

cookie

Web開發中一個很重要的議題就是如何做好用戶的整個瀏覽過程的控制,因為HTTP協議是無狀態的,所以用戶的每一次請求都是無狀態的,我們不知道在整個Web操作過程中哪些連接與該用戶有關,我們應該如何來解決這個問題呢?Web里面經典的解決方案是cookie和session,cookie機制是一種客戶端機制,把用戶數據保存在客戶端,而session機制是一種服務器端的機制,服務器使用一種類似于散列表的結構來保存信息,每一個網站訪客都會被分配給一個唯一的標志符,即sessionID,它的存放形式無非兩種:要么經過url傳遞,要么保存在客戶端的cookies里。當然,你也可以將Session保存到數據庫里,這樣會更安全,但效率方面會有所下降。

?

一、cookie的介紹

session和cookie是網站瀏覽中較為常見的兩個概念,也是比較難以辨析的兩個概念,但它們在瀏覽需要認證的服務頁面以及頁面統計中卻相當關鍵。我們先來了解一下cookie怎么來的?考慮這樣一個問題:

如何抓取一個訪問受限的網頁?如新浪微博好友的主頁,個人微博頁面等。

顯然,通過瀏覽器,我們可以手動輸入用戶名和密碼來訪問頁面,而所謂的“抓取”,其實就是使用程序來模擬完成

同樣的工作,因此我們需要了解“登陸”過程中到底發生了什么。

當用戶來到微博登陸頁面,輸入用戶名和密碼之后點擊“登錄”后瀏覽器將認證信息POST給遠端的服務器,服務器執行驗證邏輯,如果驗證通過,則瀏覽器會跳轉到登錄用戶的微博首頁,在登錄成功后,服務器如何驗證我們對其他受限制頁面的訪問呢?因為HTTP協議是無狀態的,所以很顯然服務器不可能知道我們已經在上一次的HTTP請求中通過了驗證。當然,最簡單的解決方案就是所有的請求里面都帶上用戶名和密碼,這樣雖然可行,但大大加重了服務器的負擔(對于每個request都需要到數據庫驗證),也大大降低了用戶體驗(每個頁面都需要重新輸入用戶名密碼,每個頁面都帶有登錄表單)。既然直接在請求中帶上用戶名與密碼不可行,那么就只有在服務器或客戶端保存一些類似的可以代表身份的信息了,所以就有了cookie與session。

cookie,簡而言之就是在本地計算機保存一些用戶操作的歷史信息(當然包括登錄信息),并在用戶再次訪問該站點時瀏覽器通過HTTP協議將本地cookie內容發送給服務器,從而完成驗證,或繼續上一步操作。

cookie的原理圖:

Cookie是由瀏覽器維持的,存儲在客戶端的一小段文本信息,伴隨著用戶請求和頁面在Web服務器和瀏覽器之間傳遞。用戶每次訪問站點時,Web應用程序都可以讀取cookie包含的信息。瀏覽器設置里面有cookie隱私數據選項,打開它,可以看到很多已訪問網站的cookies,如下圖所示:

?

?

?

cookie是有時間限制的,根據生命期不同分成兩種:會話cookie持久cookie

如果不設置過期時間,則表示這個cookie生命周期為從創建到瀏覽器關閉止,只要關閉瀏覽器窗口,cookie就消失了。這種生命期為瀏覽會話期的cookie被稱為會話cookie。會話cookie一般不保存在硬盤上而是保存在內存里。

如果設置了過期時間(setMaxAge(606024)),瀏覽器就會把cookie保存到硬盤上,關閉后再次打開瀏覽器,這些cookie依然有效直到超過設定的過期時間。存儲在硬盤上的cookie可以在不同的瀏覽器進程間共享,比如兩個IE窗口。而對于保存在內存的cookie,不同的瀏覽器有不同的處理方式。

?

二、Go使用cookie

Go語言中通過net/http包中的SetCookie來設置:

http.SetCookie(w ResponseWriter, cookie *Cookie)

w表示需要寫入的response,cookie是一個struct,讓我們來看一下cookie對象是怎么樣的

type Cookie struct {Name  stringValue stringPath       string    // optionalDomain     string    // optionalExpires    time.Time // optionalRawExpires string    // for reading cookies only// MaxAge=0 means no 'Max-Age' attribute specified.// MaxAge<0 means delete cookie now, equivalently 'Max-Age: 0'// MaxAge>0 means Max-Age attribute present and given in secondsMaxAge   intSecure   boolHttpOnly boolRaw      stringUnparsed []string // Raw text of unparsed attribute-value pairs
}

我們來看一個例子,如何設置cookie,以及獲取cookie

package mainimport ("net/http""fmt"
)func main() {http.HandleFunc("/setcookie", SetCookie)http.HandleFunc("/getcookie", GetCookie)http.ListenAndServe("localhost:8080", nil)}func SetCookie(w http.ResponseWriter, r *http.Request) {//設置cookiecookie := http.Cookie{Name: "name", Value: "hanru", Path: "/", MaxAge: 60}http.SetCookie(w, &cookie)w.Write([]byte("write cookie ok"))}//Go讀取cookie
func GetCookie(w http.ResponseWriter, r *http.Request) {cookie2, _ := r.Cookie("name")fmt.Fprint(w, cookie2)//還有另外一種讀取方式//for _, cookie := range r.Cookies() {//  fmt.Fprint(w, cookie.Name)//}
}

運行服務器后,打開瀏覽器輸入地址:http://127.0.0.1:8080/setcookie

運行結果如下:

?

?

?在chrome瀏覽器中執行:http://127.0.0.1:8080/setcookie, 觸發go服務執行設置cookie的動作, 瀏覽器收到這個信息后, 真正執行設置cookie, 在chrome中可查(chrome://settings/content/cookies目錄中的localhost域名中查), 如下:

?

?

可以看到,過期時間是60s, 60s后再次查的時候, 就沒有name對應的cookie項了。

接下來,我們獲取一下cookie,要在設置cookie的60s內進行獲取,否則就取不到了。

然后打開瀏覽器,輸入網址:http://127.0.0.1:8080/getcookie

運行效果如下:

我們等cookie過期消失, 然后再來玩抓包。 好,現在沒有name對應的cookie了, 我們連續兩次執行:http://127.0.0.1:8080/setcookie, 服務端tcpdump抓包,兩次的請求和響應依次如下:

第一次:

第二次:

?

可以看到,第一次請求時, 瀏覽器發出的請求中不帶cookie, 因為瀏覽器壓根就沒有這項cookie, 在go服務端的回包中攜帶了Set-Cookie首部, 瀏覽器收到這個信息后,將其寫入到瀏覽器本地, 形成cookie。

第二次請求時(因cookie的過期時間設置為了60s, 故必須在60s內發起第二次請求), 此時, 瀏覽器的http請求中自動攜帶了cookie信息,go服務端也能收到這個信息。

由此可見, cookie不過是瀏覽器端的一個環境變量而已, 僅此而已。cookie值存在于瀏覽器所在的本地電腦中。 而所謂的服務端設置cookie, 其實是服務端給瀏覽器發送對應的設置cookie信息, 由瀏覽器來真正執行設置cookie的操作, 存于本地電腦磁盤中。

?

轉載自https://www.chaindesk.cn/witbook/17/265,謝謝韓老師

轉載于:https://www.cnblogs.com/Paul-watermelon/articles/11030894.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/393196.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/393196.shtml
英文地址,請注明出處:http://en.pswp.cn/news/393196.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

PhotoKit 照片庫的管理-獲取圖像

PHAsset部分屬性解析 1、HDR 和全景照片 mediaSubtypes 屬性驗證資源庫中的圖像在捕捉時是否開啟了 HDR&#xff0c;拍攝時是否使用了相機應用的全景模式。 2、收藏和隱藏資源 要驗證一個資源是否被用戶標記為收藏或被隱藏&#xff0c;只要檢查 PHAsset 實例的 favorite 和 hid…

cmail服務器安裝后無法登錄的解決辦法

安裝cmailserver 5.4.6軟件安裝、注冊都非常順利&#xff0c;webmail頁面也都正常打開&#xff0c;但是一點“登錄”就提示錯誤&#xff1a; Microsoft VBScript 運行時錯誤 錯誤 800a01ad ActiveX 部件不能創建對象: CMailCOM.POP3.1 /mail/login.asp&#xff0c;行 42 點“…

matlab對人工智能,MATLAB與人工智能深度學習和機器學習.PDF

MATLAB與人工智能深度學習和機器學習MATLAB 與人工智能&#xff1a;深度學習有多遠&#xff1f;© 2017 The MathWorks, Inc.1機器學習8機器學習無處不在? 圖像識別 [TBD]? 語音識別? 股票預測? 醫療診斷? 數據分析? 機器人? 更多……9什么是機器學習&#xff1f;機…

leetcode1471. 數組中的 k 個最強值(排序)

給你一個整數數組 arr 和一個整數 k 。 設 m 為數組的中位數&#xff0c;只要滿足下述兩個前提之一&#xff0c;就可以判定 arr[i] 的值比 arr[j] 的值更強&#xff1a; |arr[i] - m| > |arr[j] - m| |arr[i] - m| |arr[j] - m|&#xff0c;且 arr[i] > arr[j] 請返回…

Spring中WebApplicationInitializer的理解

現在JavaConfig配置方式在逐步取代xml配置方式。而WebApplicationInitializer可以看做是Web.xml的替代&#xff0c;它是一個接口。通過實現WebApplicationInitializer&#xff0c;在其中可以添加servlet&#xff0c;listener等&#xff0c;在加載Web項目的時候會加載這個接口實…

使用fetch封裝請求_關于如何使用Fetch API執行HTTP請求的實用ES6指南

使用fetch封裝請求In this guide, I’ll show you how to use the Fetch API (ES6) to perform HTTP requests to an REST API with some practical examples you’ll most likely encounter.在本指南中&#xff0c;我將向您展示如何使用Fetch API(ES6 )來執行對REST API的 HTT…

hadoop集群中客戶端修改、刪除文件失敗

這是因為hadoop集群在啟動時自動進入安全模式 查看安全模式狀態&#xff1a;hadoop fs –safemode get 進入安全模式狀態&#xff1a;hadoop fs –safemode enter 退出安全模式狀態&#xff1a;hadoop fs –safemode leave轉載于:https://www.cnblogs.com/lishengnan/p/a123.ht…

OpenStack nova-network 支持多vlan技術實現片段代碼

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748

Rest API

什么是接口測試 接口測試又稱 API 測試 Application Programming Interface 接口測試是測試系統組件間接口的一種測試。重點關注數據傳遞。 接口測試一般會用于多系統間交互開發&#xff0c;或者擁有多個子系統的應用系統開發的測試。 為什么要做接口測試 很多系統關聯都是基于…

php循環checkbox,php循環刪除checkbox | 學步園

一、首先要了解sql語句$SQLdelete from user where id in (1,2,4);表單大概是&#xff1a;form action methodpost input nameID_Dele[] typecheckbox idID_Dele[] value1input nameID_Dele[] typecheckbox idID_Dele[] value2input nameID_Dele[] type首先要了解sql語句$SQL&q…

leetcode1451. 重新排列句子中的單詞(排序)

「句子」是一個用空格分隔單詞的字符串。給你一個滿足下述格式的句子 text : 句子的首字母大寫 text 中的每個單詞都用單個空格分隔。 請你重新排列 text 中的單詞&#xff0c;使所有單詞按其長度的升序排列。如果兩個單詞的長度相同&#xff0c;則保留其在原句子中的相對順序…

Java+Oracle實現事務——JDBC事務

J2EE支持JDBC事務、JTA事務和容器事務事務&#xff0c;這里說一下怎樣實現JDBC事務。 JDBC事務是由Connection對象所控制的&#xff0c;它提供了兩種事務模式&#xff1a;自己主動提交和手動提交&#xff0c;默認是自己主動提交。 自己主動提交就是&#xff1a;在JDBC中。在一個…

開源項目貢獻者_我如何從一名貢獻者轉變為一個開源項目維護者

開源項目貢獻者by Dhanraj Acharya通過Dhanraj Acharya 我如何從一名貢獻者轉變為一個開源項目維護者 (How I went from being a contributor to an Open Source project maintainer) I was a lone software developer. When I was in college, I attended the KDE conference…

網絡攝像頭CVE

CVE-2018-9995 rtsp未授權訪問 rtsp后綴整理&#xff1a; Axis&#xff08;安訊士&#xff09; rtsp:// 192.168.200.202/axis-media/media.amp?videocodech264&resolution1280x720 rtsp://IP地址/mpeg4/media.amp rtsp://IP地址/安迅士/AXIS-media/media.amp123D-Link …

Centos中不從skel目錄里向其中復制任何文件錯誤的解決方法

[rootlocalhost www]# useradd -d /webserver/www/ ithovcom useradd&#xff1a;警告&#xff1a;此主目錄已經存在。 不從 skel 目錄里向其中復制任何文件。 [rootlocalhost www]# ls -a .&http://www.aliyun.com/zixun/aggregation/37954.html">nbsp; .. 發現沒…

leetcode91. 解碼方法

一條包含字母 A-Z 的消息通過以下方式進行了編碼&#xff1a; ‘A’ -> 1 ‘B’ -> 2 … ‘Z’ -> 26 給定一個只包含數字的非空字符串&#xff0c;請計算解碼方法的總數。 示例 1: 輸入: “12” 輸出: 2 解釋: 它可以解碼為 “AB”&#xff08;1 2&#xff09;或者…

php 系統平均負載,Linux_解析Linux系統的平均負載概念,一、什么是系統平均負載(Load a - phpStudy...

解析Linux系統的平均負載概念一、什么是系統平均負載(Load average)&#xff1f;在Linux系統中&#xff0c;uptime、w、top等命令都會有系統平均負載load average的輸出&#xff0c;那么什么是系統平均負載呢&#xff1f;系統平均負載被定義為在特定時間間隔內運行隊列中的平均…

Elastic-job使用及原理

一、原理 elastic-job有lite版和cloud版&#xff0c;最大的區別是有無調度中心&#xff0c;筆者采用的是lite版本&#xff0c;無中心化。 tips: 第一臺服務器上線觸發主服務器選舉。主服務器一旦下線&#xff0c;則重新觸發選舉&#xff0c;選舉過程中阻塞&#xff0c;只有主服…

構建持續交付_如何使交付成為您的重點將如何幫助您構建高質量的應用程序

構建持續交付by Simon Schwartz西蒙施瓦茨(Simon Schwartz) 如何使交付成為您的重點將如何幫助您構建高質量的應用程序 (How making delivery your focus will help you build quality applications) I was recently asked by our company’s executive team why our team was…

微信退款通知,退款回調數據解密.SHA256簽名AEAD_AES_256_GCM解密

$xmlResult file_get_contents("php://input");//獲取微信的數據$result $this->xmlToArray($xmlResult);//將xml轉成數組 // 將加密的數據解密,方法在下面$reqInfo $this->refund_decrypt($result[req_info]); /** 退款通知解密* Author WangZhaoBo* param…