用GO語(yǔ)言(golang)寫(xiě)了一個(gè)簡(jiǎn)單的Web服務(wù),但是始終無(wú)法獲取Cookie的值
站在用戶的角度思考問(wèn)題,與客戶深入溝通,找到柞水網(wǎng)站設(shè)計(jì)與柞水網(wǎng)站推廣的解決方案,憑借多年的經(jīng)驗(yàn),讓設(shè)計(jì)與互聯(lián)網(wǎng)技術(shù)結(jié)合,創(chuàng)造個(gè)性化、用戶體驗(yàn)好的作品,建站類型包括:成都做網(wǎng)站、網(wǎng)站建設(shè)、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣、域名注冊(cè)、網(wǎng)絡(luò)空間、企業(yè)郵箱。業(yè)務(wù)覆蓋柞水地區(qū)。
現(xiàn)象如下:
使用Chrome的開(kāi)發(fā)者工具觀察Cookie可以看到設(shè)置的Cookie的值
使用r.Cookie(CookieName)無(wú)法取得Cookie內(nèi)容,錯(cuò)誤信息:http: named cookie not present
在服務(wù)器端打印Requset結(jié)構(gòu),結(jié)果中沒(méi)有設(shè)置的Cookie值
最后Google了一下,在golang-nuts的論壇里找到了解決方法。
根本原因在于GO語(yǔ)言(golang)不能獲取值中帶有空格的Cookie
而且會(huì)將Cookie中的一些特殊字符替換為空格
//src/pkg/net/http.go
func (c *Cookie) String() string {
...
fmt.Fprintf(b, "%s=%s", sanitizeName(c.Name), sanitizeValue(c.Value))
...
}
...
var cookieValueSanitizer = strings.NewReplacer("\n", " ", "\r", " ", ";", " ")
...
func sanitizeValue(v string) string {
return cookieValueSanitizer.Replace(v)
}
俺就是使用了分號(hào)。。。
另外討論中提到的不要使用指針傳遞http.ResponseWriter的問(wèn)題,
我試了一下,使用指針傳遞http.ResponseWriter不會(huì)對(duì)Cookie的設(shè)置和取得產(chǎn)生影響
不過(guò)很多函數(shù)需要的都是http.ResponseWriter的對(duì)象,如果傳指針,很多地方要寫(xiě)*http.ResponseWriter著實(shí)也挺麻煩
互聯(lián)網(wǎng)隱私一直是一個(gè)敏感話題。很多爆炸新聞或者香艷的丑聞,似乎就像病毒一樣每隔一段時(shí)間就爆發(fā)。這不僅是網(wǎng)民茶余飯后的談資調(diào)侃,也讓部分安全公司開(kāi)始吵作。用戶在安全,隱私,cookie之類宣傳攻勢(shì),不知所以。有的人認(rèn)為cookie是泄露隱私的元兇。對(duì)于開(kāi)發(fā)者,cookie的是web開(kāi)發(fā)里程上的一大發(fā)明,cookie是小甜點(diǎn),絕不是惡魔。但是,如果使用不當(dāng),小甜點(diǎn)發(fā)霉了一樣會(huì)有毒。
Cookie的誕生挺有意思。試想一下,當(dāng)我們?nèi)ャy行辦業(yè)務(wù)的時(shí)候,銀行職員會(huì)提供一個(gè)卡號(hào),待會(huì)較叫號(hào)的時(shí)候,拿著卡號(hào)給柜臺(tái)業(yè)務(wù)員。這樣簡(jiǎn)單的一種”認(rèn)證“,就是cookie的一種應(yīng)用。
web開(kāi)發(fā)免不了要和cookie打交道。go的http庫(kù)也提供了cookie的相關(guān)操作。
Name字段為cookie的名字,Value是其值,剩下的Path和Domain則是cookie的存儲(chǔ)的范圍。Expires是cookie的過(guò)期時(shí)間,如果不設(shè)置,那么這是一個(gè)session型的cookie,即瀏覽器會(huì)話有用,一旦關(guān)閉瀏覽器,cookie隨即會(huì)被刪除。
cookie是header一項(xiàng)內(nèi)容,因此可以使用reponse的Header方法設(shè)置cookie。
這里也可以測(cè)試驗(yàn)證 Set和Add兩個(gè)方法的差別。當(dāng)然,和文件上傳類似,go也提供了常用的工具函數(shù)。
http的SetCookie方法也可以設(shè)置cookie,就不需要關(guān)系Set和Add的先后順序了,當(dāng)然第二個(gè)參數(shù)是一個(gè)Cookie的指針對(duì)象。設(shè)置了cookie,接下來(lái)就是需要讀cookie。
讀取cookie的方式也有很多,cookie封裝在header中,當(dāng)然可以通過(guò)header方法處理。
不使用Header方法,也可以使用Request的方法:
訪問(wèn)的時(shí)候可以發(fā)現(xiàn),r.Cookie返回了對(duì)于key的鍵值對(duì),而r.Cookies則返回了所有cookie的key的鍵值對(duì)值。
cookie的作用很多,通常記錄客戶端的一些信息,用來(lái)做用戶的登錄驗(yàn)證?,F(xiàn)在我們需要使用cookie來(lái)做一個(gè)小特性---消息。通常web請(qǐng)求發(fā)出后,response返回?cái)?shù)據(jù),也可以設(shè)置一些消息用來(lái)指引用戶。
setMessageHandler 函數(shù)很簡(jiǎn)單,就是創(chuàng)建一個(gè)cookie實(shí)例,然后把消息寫(xiě)入到cookie,然后再返回給客戶端。
getMessageHandler首先會(huì)讀取key為flash的cookie,如果沒(méi)讀到內(nèi)容,則表示消息不存在,否則就創(chuàng)建另外一個(gè)cookie,設(shè)置其過(guò)期時(shí)間這里等于清除cookie。然后把讀取出來(lái)的message返回給客戶端。完成消息通信。
我們討論了go中cookie的基本應(yīng)用?,F(xiàn)在的web開(kāi)發(fā)中,人們?cè)絹?lái)越重視網(wǎng)絡(luò)安全,因此cookie的安全也成為用戶關(guān)心的內(nèi)容。go原生的cookie封裝比較簡(jiǎn)單。go的社區(qū)卻開(kāi)發(fā)了很多輪子,實(shí)現(xiàn)了secure cookie,例如gorilla/securecookie庫(kù)。實(shí)際開(kāi)發(fā)中,可能會(huì)借助一些三方的庫(kù)或包來(lái)完成功能。
cookie用來(lái)做認(rèn)證需要跟用戶有交互,承載交互的當(dāng)然是用戶界面。既然是關(guān)于用戶界面,學(xué)習(xí)go的模板技術(shù)就是順其自然之事。雖然現(xiàn)在前后端分離技術(shù),傳統(tǒng)的模板技術(shù)已經(jīng)逐步被前端渲染取代了,但是對(duì)于一些同構(gòu)項(xiàng)目,還是依賴部分服務(wù)端模板渲染。下一個(gè)話題再討論go的模板。
相關(guān)閱讀:
cookie wiki
全面解讀HTTP Cookie
Cookie由后端管理。
問(wèn)題:第一次set cookie可以生效,第二次覆蓋或者清除cookie卻不生效。查看瀏覽器的cookie信息,仍然是第一次的值。
cookie := http.Cookie{
? ? ? ? ? ? Name:? ? name,
? ? ? ? ? ? Value:? ? value,
? ? ? ? ? ? HttpOnly: true,
? ? ? ? ? ? Secure:? false,
? ? ? ? ? ? Path:? ? "/",
? ? }
? ? http.SetCookie(resp, cookie)
原因:在第二次設(shè)置cookie,即清除cookie時(shí),沒(méi)有設(shè)置Path
cookie := http.Cookie{
? ? ? ? ? ? Name:? name,
? ? ? ? ? ? MaxAge: -1,
? ? ? ? ? ? Expires: time.Unix(1, 0),
? ? }
? ? http.SetCookie(resp, cookie)
解決方案:
在清除Cookie時(shí),添加Path,并且與第一次設(shè)置時(shí)的Path值一致。
用Session啊,用各種WEB框架的話可以使用框架提供的Session支持。如果是原生的就自己實(shí)現(xiàn)。各種框架都是用Cookies實(shí)現(xiàn)的,有用戶訪問(wèn)就設(shè)置一個(gè)唯一的Cookie,把對(duì)應(yīng)的用戶信息保存起來(lái)。同理用戶登錄時(shí)就把登錄信息也保存到Session里。