項目實戰(zhàn)(連載):基于Angular2+Mongodb+Node技術(shù)實現(xiàn)的多用戶博客系統(tǒng)教程(10)

本章主要講什么(一句話)?

本章主要講解:重構(gòu)Node后臺加入Session支持及前臺跨域訪問配置

一但金、前言

上一章主要對項目的路由功能進(jìn)行完善:登錄路由层扶,注冊路由,發(fā)表文章路由诊笤,獲取用戶信息路由等,本章會繼續(xù)對于本項目的Node部分功能進(jìn)行完善巾陕。本將也將會是最后一章關(guān)于Node讨跟,Mongose相關(guān)技術(shù)及代碼的講解,下一章起鄙煤,將正式啟動angular2的前端部分许赃,敬請期待 :)

二、本章技術(shù)關(guān)健詞

Node馆类、MongoDB、Angular2弹谁、Mongoose乾巧、Route、Session预愤、跨域

三沟于、本章涉及核心技術(shù)點

四、內(nèi)容

4.1植康、Session

4.1.1旷太、為什么需要Session?

? ? ?cookie雖然很方便销睁,但是使用cookie有一個很大的弊端供璧,cookie中的所有數(shù)據(jù)在客戶端就可以被修改,數(shù)據(jù)非常容易被偽造冻记,那么一些重要的數(shù)據(jù)就不能存放在cookie中了睡毒,而且如果cookie中數(shù)據(jù)字段太多會影響傳輸效率。為了解決這些問題冗栗,就產(chǎn)生了session演顾,session中的數(shù)據(jù)是保留在服務(wù)器端的供搀。HTTP協(xié)議(http://www.w3.org/Protocols/)是“一次性單向”協(xié)議。服務(wù)端不能主動連接客戶端钠至,只能被動等待并答復(fù)客戶端請求葛虐。客戶端連接服務(wù)端棉钧,發(fā)出一個HTTP Request屿脐,服務(wù)端處理請求,并且返回一個HTTP Response給客戶端掰盘,本次HTTP Request-Response?Cycle結(jié)束摄悯。 我們看到,HTTP協(xié)議本身并不能支持服務(wù)端保存客戶端的狀態(tài)信息愧捕。于是奢驯,Web Server中引入了session的概念,用來保存客戶端的狀態(tài)信息次绘。

4.1.2瘪阁、什么是Session?

Session:在計算機(jī)中邮偎,尤其是在網(wǎng)絡(luò)應(yīng)用中管跺,稱為“會話”。Session直接翻譯成中文比較困難禾进,一般都譯成時域豁跑。在計算機(jī)專業(yè)術(shù)語中,Session是指一個終端用戶與交互系統(tǒng)進(jìn)行通信的時間間隔泻云,通常指從注冊進(jìn)入系統(tǒng)到注銷退出系統(tǒng)之間所經(jīng)過的時間艇拍。具體到Web中的Session指的就是用戶在瀏覽某個網(wǎng)站時,從進(jìn)入網(wǎng)站到瀏覽器關(guān)閉所經(jīng)過的這段時間宠纯,也就是用戶瀏覽這個網(wǎng)站所花費(fèi)的時間卸夕。因此從上述的定義中我們可以看到,Session實際上是一個特定的時間概念婆瓜。

4.1.3快集、Session的工作原理

一個session就是一系列某用戶和服務(wù)器間的通訊。服務(wù)器有能力分辨出不同的用戶廉白。一個session的建立是從一個用戶向服務(wù)器發(fā)第一個請求開始个初,而以用戶顯式結(jié)束或session超時為結(jié)束。

其工作原理是這樣的:

1.當(dāng)一個用戶向服務(wù)器發(fā)送第一個請求時猴蹂,服務(wù)器為其建立一個session勃黍,并為此session創(chuàng)建一個標(biāo)識號;

2.這個用戶隨后的所有請求都應(yīng)包括這個標(biāo)識號晕讲。服務(wù)器會校對這個標(biāo)識號以判斷請求屬于哪個session覆获。這種機(jī)制不使用IP作為標(biāo)識马澈,是因為很多機(jī)器是通過代理服務(wù)器方式上網(wǎng),沒法區(qū)分每一臺機(jī)器弄息。

形象比喻:

? ? ?這里用一個形象的比喻來解釋session的工作方式痊班。假設(shè)Web Server是一個商場的存包處,HTTP Request是一個顧客摹量,第一次來到存包處涤伐,管理員把顧客的物品存放在某一個柜子里面(這個柜子就相當(dāng)于Session),然后把一個號碼牌交給這個顧 客缨称,作為取包憑證(這個號碼牌就是Session?ID)凝果。顧客(HTTP Request)下一次來的時候,就要把號碼牌(Session ID)交給存包處(Web Server)的管理員睦尽。管理員根據(jù)號碼牌(Session ID)找到相應(yīng)的柜子(Session)器净,根據(jù)顧客(HTTP Request)的請求,Web Server可以取出当凡、更換山害、添加柜子(Session)中的物品,Web Server也可以讓顧客(HTTP Request)的號碼牌和號碼牌對應(yīng)的柜子(Session)失效沿量。顧客(HTTP Request)的忘性很大浪慌,管理員在顧客回去的時候(HTTP Response)都要重新提醒顧客記住自己的號碼牌(Session ID)。這樣朴则,顧客(HTTP Request)下次來的時候权纤,就又帶著號碼牌回來了。

4.1.4乌妒、express中的Session

express中操作session要用到express-session

(https://github.com/expressjs/session )這個模塊汹想,主要的方法就是session(options),其中options中包含可選參數(shù)芥被,主要有:

?name:設(shè)置cookie中,保存session的字段名稱坐榆,默認(rèn)為connect.sid拴魄。

?store:

session的存儲方式,默認(rèn)存放在內(nèi)存中席镀,也可以使用redis匹中,mongodb等。express生態(tài)中都有相應(yīng)模塊的支持豪诲。

?secret:通過設(shè)置的secret字符串顶捷,來計算hash值并放在cookie中,使產(chǎn)生的signedCookie防篡改屎篱。

?cookie:設(shè)置存放session id的cookie的相關(guān)選項服赎,默認(rèn)為

(default: { path: '/', httpOnly: true,secure: false, maxAge: null })

genid:產(chǎn)生一個新的session_id時葵蒂,所使用的函數(shù),默認(rèn)使用uid2這個npm包重虑。

?rolling:每個請求都重新設(shè)置一個cookie践付,默認(rèn)為false。

?resave:即使session沒有被修改缺厉,也保存session值永高,默認(rèn)為true。

express-session默認(rèn)使用內(nèi)存來存session提针,對于開發(fā)調(diào)試來說很方便

注意:在Express4.x中使用session時要額外安裝express-session包:

兩種安裝方式:

第一種:cnpm install express-session

第二種:package.json包中加入"express-session":"~1.14.1"

到其對應(yīng)目錄下執(zhí)行:npm install命令

var app = express();

var session= require('express-session');

app.listen(5000);

//按照上面的解釋命爬,設(shè)置session的可選參數(shù)

app.use(session({

secret: 'recommand 128 bytes random string', //建議使用128個字符的隨機(jī)字符串

cookie: { maxAge: 60 * 1000 }

}));

app.get('/', function (req, res) {

//檢查session中的isVisit字段

//如果存在則增加一次,否則為session設(shè)置isVisit字段辐脖,并初始化為1饲宛。

if(req.session.isVisit) {

req.session.isVisit++;

res.send('

第' + req.session.isVisit + '次來此頁面

');

} else {

req.session.isVisit = 1;

res.send("歡迎第一次來這里");

console.log(req.session);

}

});

4.1.4、項目中Session的代碼

? ? 基本上跟上述的配置大同小異揖曾,在這里不累述落萎,后面大家可以直接看代碼!此處略

4.2炭剪、跨域?

4.2.1练链、什么是跨域?

概念:只要協(xié)議奴拦、域名媒鼓、端口有任何一個不同,都被當(dāng)作是不同的域错妖。

URL ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 說明 ? ? ? ? ? ? ? ? ? ? ?是否允許通信

http://www.a.com/a.js

http://www.a.com/b.js ? ? ? ? ? ? ? 同一域名下 ? ? ? ? ? ? ? ? ? ? ? 允許

http://www.a.com/lab/a.js

http://www.a.com/script/b.js ? ? 同一域名下不同文件夾 ? ? 允許

http://www.a.com:8000/a.js

http://www.a.com/b.js ? ? ? ? ? ? ? ? ?同一域名绿鸣,不同端口 ? ? ?不允許

http://www.a.com/a.js

https://www.a.com/b.js ? ? ? ? ? ? ? ? ? 同一域名,不同協(xié)議 ? ? 不允許

http://www.a.com/a.js

http://70.32.92.74/b.js ? ? ? ? ? ? ? ? ? ? ? ?域名和域名對應(yīng)ip ? ? ? 不允許

http://www.a.com/a.js

http://script.a.com/b.js ? ? ? ? ? ? ? ? ? ? ? ?主域相同暂氯,子域不同 ? ? 不允許

http://www.a.com/a.js

http://a.com/b.js ? ? ? ? ? ? ? ? ? 同一域名潮模,不同二級域名(同上) ? ? ? 不允許(cookie這種情況下也不允許訪問)

http://www.cnblogs.com/a.js

http://www.a.com/b.js ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?不同域名 ? ? ? ? ? ? ? 不允許

4.2.2、為什么瀏覽器不支持跨域請求

主要的原因還是安全性痴施,防止CSRF攻擊擎厢。

CSRF是什么?

? ? CSRF(Cross-site request forgery)辣吃,中文名稱:跨站請求偽造动遭,也被稱為:one click attack/session riding,縮寫為:CSRF/XSRF神得。

CSRF可以做什么厘惦?

? ?你這可以這么理解CSRF攻擊:攻擊者盜用了你的身份,以你的名義發(fā)送惡意請求哩簿。CSRF能夠做的事情包括:以你名義發(fā)送郵件宵蕉,發(fā)消息酝静,盜取你的賬號,甚至于購買商品国裳,虛擬貨幣轉(zhuǎn)賬......造成的問題包括:個人隱私泄露以及財產(chǎn)安全形入。

4.2.3、跨域的幾種解決辦法

解決跨域訪問的辦法有N種缝左,最常用的為以下幾種:

1> document.domain + iframe? ? ? (只有在主域相同的時候才能使用該方法)

2> 動態(tài)創(chuàng)建script

3> location.hash + iframe

4> window.name + iframe

5> postMessage(HTML5中的XMLHttpRequest Level 2中的API)

6> CORS

7> JSONP

8> web sockets

要想了解以上8種的具體實現(xiàn)亿遂,可以參考此篇文章:http://blog.csdn.net/joyhen/article/details/21631833

但就像知道孔乙已的茴香豆的幾種寫法一樣,我認(rèn)為沒有太大的意義渺杉,我們更看重的怎么樣解決問題蛇数。

根據(jù)我個人的工作經(jīng)驗,在解決跨域時無外乎兩種是越,一種是客戶端想辦法耳舅,如使用JosnP(這個后面講Angular2時我會給大家演示),另一種在服務(wù)器端想辦法倚评,做配置 浦徊。相比較而言,第二種會配置更靈活天梧,功能更強(qiáng)大盔性,所以這里我主要給大家演示第二種方式。

4.2.4呢岗、Node中前端JS跨域配置代碼

好冕香,重點來了,直接上代碼:

打開index.js,找到以下代碼段:

var crypto = require('crypto'),

User = require('../models/user.js'),

Post = require('../models/post.js');

settings = require('../settings');

module.exports = function(app) {

? ? //此處我們將加入跨域代碼配置

}

在上述注釋處加入以下代碼:

app.all('*', function(req, res, next) {

res.header('Access-Control-Allow-Origin',settings.client);

res.header('Access-Control-Allow-Headers', 'Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild');

res.setHeader("Access-Control-Max-Age", "3600");

res.setHeader("Access-Control-Allow-Credentials", "true"); //是否支持cookie跨域

next();

});

//跨域預(yù)檢查所有的get請求

app.all('/get/*', function(req, res, next) {

res.header('Access-Control-Allow-Methods', 'GET,OPTIONS');

if (req.method == 'OPTIONS') {

res.send(200);

} else {

console.log(req.method);

next();

}

});

//跨域預(yù)檢查所有的post請求

app.all('/post/*', function(req, res, next) {

res.header('Access-Control-Allow-Methods', 'POST,OPTIONS');

if (req.method == 'OPTIONS') {

res.send(200);

} else {

console.log(req.method);

next();

}

});

1. app.all('*', function(req, res, next) {后豫。悉尾。。}

app.all('/get/*', function(req, res, next) {挫酿。构眯。。}

app.all('/post/*', function(req, res, next) {早龟。惫霸。。}

注意:第一行 * 代表拄衰,所有前端路由請求它褪,必須經(jīng)過此“過濾器”攔截處理

/get/*饵骨,代表所有以get打頭的路由請求翘悉,必須經(jīng)過此“過濾器”攔截處理,如:http://localhost:8800/get/user?name=zzz ?居触,這個請求就會被 此“過濾器”攔截

/post/*妖混,代表所有以post打頭的路由請求老赤,必須經(jīng)過此“過濾器”攔截處理,如:http://localhost:8800/post/reg 制市,這個請求就會被 此“過濾器”攔截

2. res.header('Access-Control-Allow-Origin',settings.client);

這種代碼的作用是:只有當(dāng)目標(biāo)頁面的response中抬旺,包含了Access-Control-Allow-Origin這個header,并且它的值里有我們自己的域名時祥楣,瀏覽器才允許我們拿到它頁面的數(shù)據(jù)進(jìn)行下一步處理开财,即設(shè)置 “同源策略“, 如果它的值設(shè)為*,則表示誰都可以用:Access-Control-Allow-Origin: *,但一般我們不會這么干误褪,出于安全性考慮责鳍,最好還是設(shè)定你允許訪問的網(wǎng)站

這名代碼相當(dāng)于設(shè)置了:

Access-Control-Allow-Origin : http://localhost:3000

注意settings.client的配置:

settings.js

module.exports = {

cookieSecret: 'myblog',

db: 'blog',

host: 'localhost',

port: 27017,

client:'http://localhost:3000'? //用于設(shè)置跨域

};

3. res.header('Access-Control-Allow-Headers', 'Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild');

OPTIONS請求頭部中會包含以下頭部:Origin、Access-Control-Request-Method兽间、Access-Control-Request-Headers历葛,發(fā)送這個請求后,服務(wù)器可以設(shè)置如下頭部與瀏覽器溝通來判斷是否允許這個請求嘀略。yourHeaderFeild 這個表示你可以自定義與瀏覽器客戶端溝通的信息恤溶。

4. res.setHeader("Access-Control-Max-Age", "3600");

Access-Control-Max-Age: 3600?// 表明在3600秒內(nèi),不需要再發(fā)送預(yù)檢驗請求帜羊,可以緩存該結(jié)果,即CORS緩存配置

5. res.setHeader("Access-Control-Allow-Credentials", "true"); //是否支持cookie跨域,ture代表支持咒程,注意這個配置很重要,不然后面我們和Angular2 Http請求時逮壁,發(fā)現(xiàn)不配置此項無法進(jìn)行服務(wù)端的Session操作

6. Access-Control-Allow-Methods : 表明它允許GET孵坚、POST、PUT窥淆、DELETE的外域請求

注意app.all('/get/*'卖宠。。忧饭。)與 app.all('/post/*',扛伍。。词裤。)里面的內(nèi)容的區(qū)別刺洒,這樣做的目的,主要還是從更高效和更安全的角度去考慮的

7. 注意吼砂,上面各個 ” 過濾器“里的 next() 不可省

五逆航、后述

? ? ?好了,項目到了這里渔肩,關(guān)于Node與MongoDB操作部分內(nèi)容因俐,已經(jīng)基本全部結(jié)束,希望大家能夠有所收獲,后繼我們將繼續(xù)Angular2部分抹剩,因近期工作比較忙撑帖,所以更新文章有些慢,大家見諒澳眷,大家支持的話胡嘿,可以給我點贊,評論钳踊,轉(zhuǎn)發(fā)衷敌,您的支持將會是持續(xù)下去的動力!

本章代碼下載:http://pan.baidu.com/s/1dFf22yt

下章劇透:

《項目實戰(zhàn):基于Angular2+Mongodb+Node技術(shù)實現(xiàn)的多用戶博客系統(tǒng)教程(11)》

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?-- ?Angular2前臺框架搭建

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末拓瞪,一起剝皮案震驚了整個濱河市逢享,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌吴藻,老刑警劉巖瞒爬,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異沟堡,居然都是意外死亡侧但,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進(jìn)店門航罗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來禀横,“玉大人,你說我怎么就攤上這事粥血“爻” “怎么了?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵复亏,是天一觀的道長趾娃。 經(jīng)常有香客問我,道長缔御,這世上最難降的妖魔是什么抬闷? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任,我火速辦了婚禮耕突,結(jié)果婚禮上笤成,老公的妹妹穿的比我還像新娘。我一直安慰自己眷茁,他們只是感情好炕泳,可當(dāng)我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著上祈,像睡著了一般培遵。 火紅的嫁衣襯著肌膚如雪挣磨。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天荤懂,我揣著相機(jī)與錄音,去河邊找鬼塘砸。 笑死节仿,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的掉蔬。 我是一名探鬼主播廊宪,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼女轿!你這毒婦竟也來了箭启?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤蛉迹,失蹤者是張志新(化名)和其女友劉穎傅寡,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體北救,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡荐操,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了珍策。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片托启。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖攘宙,靈堂內(nèi)的尸體忽然破棺而出屯耸,到底是詐尸還是另有隱情,我是刑警寧澤蹭劈,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布疗绣,位于F島的核電站,受9級特大地震影響铺韧,放射性物質(zhì)發(fā)生泄漏持痰。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一祟蚀、第九天 我趴在偏房一處隱蔽的房頂上張望工窍。 院中可真熱鬧,春花似錦前酿、人聲如沸患雏。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽淹仑。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間匀借,已是汗流浹背颜阐。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留吓肋,地道東北人凳怨。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像是鬼,于是被迫代替她去往敵國和親肤舞。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,722評論 2 345

推薦閱讀更多精彩內(nèi)容