Express
基于Node.js 平臺,快速浊伙、開放谤职、極簡的 web 開發(fā)框架。
-
新建項(xiàng)目文件夾
mkdir express-node
-
初始化項(xiàng)目
//因?yàn)槭莕ode項(xiàng)目齐莲,需要初始化一下痢站,生成package.json文件 npm init -y // -y 表示使用默認(rèn),和無腦回車相同选酗。
-
安裝express
npm install express --save
-
切換鏡像源小工具
npm install nrm //解決安裝過慢問題 nrm ls //展示所有鏡像源 例: nrm use taobao //切換淘寶鏡像源 // 如果自己發(fā)布包到npm阵难,需要再切換回來
-
Express 應(yīng)用生成器
Express 應(yīng)用生成器-文檔npm install express-generator --save-dev //不需要全局,有的機(jī)器會需要權(quán)限 全局安裝了 express 運(yùn)行 未全局安裝 ./node_modules/express-generator/bin/express-cli.js 運(yùn)行 ./node_modules/express-generator/bin/express-cli.js ./ -f -e //在當(dāng)前目錄下強(qiáng)制創(chuàng)建ejs模板引擎 -h 查看所有模板引擎 //會創(chuàng)建文件夾:bin芒填、public呜叫、routes、views 提示安裝依賴 install dependencies: $ cd ./ && npm install npm install //安裝依賴
-
啟動服務(wù)器
方法一: npm start // 啟動服務(wù)器 ==>瀏覽器打開 http://localhost:3000/ 方法二: node bin/www
-
改變端口號
// 因?yàn)閚pm start 才可以啟動服務(wù)器殿衰, 在package.json文件中 start: "node ./bin/www" 在bin/www中 port = normalizePort(process.env.PORT || '3000'); 3000就是端口號 或者啟動的時(shí)候 PORT=4000 node bin/www 啟動端口為4000 80端口是默認(rèn)的端口朱庆,如果使用需要權(quán)限,需要再前面加 sudo window 需要權(quán)限闷祥,需使用管理員身份運(yùn)行
-
app.js
app.set('views', path.join(__dirname, 'views')); // 把views設(shè)置為當(dāng)前模板路徑 app.set('view engine', 'ejs'); // 模板引擎 ejs // 中間鍵 app.use(express.static(path.join(__dirname, 'public'))); 不走路由(routes文件夾)娱颊,直接從public中獲取 //路由 app.use('/', index); app.use('/users', users);
MVC
控制路由跳轉(zhuǎn)的就是控制器
視圖 views 的模板 就是V
通過C去控制請求的流向,通過M去獲取數(shù)據(jù)凯砍,通過V去把數(shù)據(jù)渲染好箱硕,展示給用戶。-
Express
- 路由
路由 - 中間鍵
使用中間件 - 模板引擎
在 Express 中使用模板引擎
views下的index.ejs就是模板果覆,處理數(shù)據(jù)轉(zhuǎn)化的就是模板引擎
-------------此處需要整理一片ejs語法博客颅痊。
- 路由
-
靜態(tài)頁面
public文件夾中的靜態(tài)文件, app.use(express.static(path.join(__dirname, 'public'))); static 設(shè)置靜態(tài)資源局待,從public中查找對應(yīng)文件夾斑响,根據(jù)文件夾目錄進(jìn)行查找 如果找到了,就表示要的是文件钳榨,就把文件傳輸過來舰罚,不再往下查找 例:注釋app.use(express.static(path.join(__dirname, 'public'))); app.use('/stylesheets/style.css',function(req,res(){ res.send('get style.css...') })) //就會走路由,把get style.css...傳到頁面薛耻。不注釋营罢,就會傳文件。
換句話說:用戶請求的任何東西,對這個(gè)網(wǎng)站來說都是路由饲漾,static是專門對靜態(tài)資源進(jìn)行的攔截蝙搔,發(fā)現(xiàn)路徑和文件夾匹配上了,傳輸文件考传。所以吃型,后綴名沒有任何意義,只是給用戶分辨而已僚楞。
新建src 文件夾
目的勤晚,使用webpack編譯到public文件夾中,顯示給用戶-
搭建簡單測試環(huán)境
index.js var obj = require('../mod/b.js') console.log(obj) a.js module.exports.a='aaaaa' b.js var a = require('./a.js').a module.exports = { b: 'bbbb', a: a } webpack.config.js var webpack = require('webpack') var path = require('path') module.exports = { entry: path.join(__dirname,"js/app/index.js"), output:{ path: path.join(__dirname,"../public/js"), filename: "index.js" } }
-
webpack壓縮
安裝webpack npm install webpack --save-dev 在package.json的script中添加 "webpack":"webpack --config=src/webpack.config.js" npm run webpack 壓縮路徑public/js/index.js泉褐,檢查文件代碼是否壓縮成功
-
自動上傳小工具
每次執(zhí)行npm run webpack 太麻煩赐写,使用自動上傳小工具,每次更改自動上傳 npm install --save-dev onchange 在package.json的script中添加 "watch": "onchange src/**/*.js src/**/*.less -- npm run webpack " npm run watch 運(yùn)行自動壓縮
-
切換node.js版本小工具
npm install -g n n 6.10.0 切換版本
-
新建toast板塊膜赃,提示便利貼增刪改查狀態(tài)
- src --> mod --> toast.js
function toast(msg,time){ this.msg = msg; this.dismissTime = time||1000, this.createToast(); this.showToast(); } toast.prototype = { createToast: function(){ var tpl = '<div class="toast">'+this.msg+'</div>'; this.$toast = $(tpl); $('body').append(this.$toast); }, showToast:function(){ var self = this; this.$toast.fadeIn(300,function(){ setTimeout(function(){ self.$toast.fadeOut(300,function(){ self.$toast.remove(); }); },self.dismissTime); }) } } function Toast(msg,time){ return new toast(msg,time); } Toast('hello') module.exports.Toast = Toast;
- src --> less --> toast.js
.toast{ position: fixed; left: 50%; transform: translateX(-50%); bottom: 20px; color: #D15A39; background: #fff; padding: 5px 10px; border-radius: 3px; box-shadow: 0px 0px 3px 1px rgba(255,255,255,0.6); display: none; }
-
-
運(yùn)行toast
刪除a.js b.js index.js ===> var Toast = require('../mod/toast.js').Toast; Toast('hello world') 在src ==> js ==> lib ==>添加jQuery 在toast.js中添加 var $ = require('../lib/jquery.min.js') 引用jQuery 簡化引入jQuery代碼 在webpack.config.js中添加 resolve:{ alias:{ //當(dāng)require引入模塊的時(shí)候挺邀,簡化路徑 jquery: path.join(__dirname,"js/lib/jquery.min.js"), mod: path.join(__dirname,"js/mod"), less: path.join(__dirname,"less") } }, toast.js代碼var $ = require('../lib/jquery.min.js') 改成 var $ = require('jquery') 在webpack.config.js中添加 plugins: [ //所有頁面都可以使用jQuery new webpack.ProvidePlugin({ $: 'jquery' }), ] toast.js代碼var $ = require('jquery') 刪除也可以使用jQuery了。 在toast.js中添加require('less/toast.less'),使用less 在webpack.config.js中添加 module:{ rules: [ { //當(dāng)require一個(gè)東西的時(shí)候财剖,會進(jìn)行檢測 test: /\.less$/, //正則表達(dá)式悠夯,以less為后綴 use: ["style-loader","css-loader","less-loader"] //使用這些loader,向前解析 less解析成css躺坟,放到頁面上 } ] }, npm install --save css-loader less-loader style-loader less 安裝 使用less
-
新建event.js(src ==> js ==> mod == event.js)
// 設(shè)計(jì)模式:發(fā)布訂閱模式;用于組件之間進(jìn)行一個(gè)解耦 var EventCenter = (function(){ var event = {}; function on(evt,handler){ events[evt] = events[evt] || []; events[evt].push({ handler: handler }); } function fire(evt,args){ if(!events[evt]){ return } for(var i = 0;i>events[evt].length;i++){ events[evt][i].handler(args); } } return { on: on, fire:fire } })();
-
新建waterfall.js(src ==> js ==> mod == waterfall.js)
//瀑布流布局 var WaterFall = (function(){ var $ct; var $items; function render($c){ $ct = $c; $items = $ct.children(); var nodeWidth = $items.outerWidth(true), colNum = parseInt($(window).width()/nodeWidth), colSumHeight = []; for(var i = 0 ;i<colNum;i++){ colSumHeight.push(0); } $items.each(function(){ var $cur = $(this); // colSumHeight = [100, 250, 80 , 200] var idx = 0, minSumHeight = colSumHeight[0]; for(var i = 0;i<colSumHeight.length;i++){ if(colSumHeight[i] < minSumHeight){ idx = i; minSumHeight = colSumHeight[i]; } } $cur.css({ left: nodeWidth*idx, top: minSumHeight }); colSumHeight[idx] = $cur.outerWidth(true) + colSumHeight[idx]; }); } $(window).on('resize',function(){ render($ct); }) return{ init: render } })() // WaterFall.init($('#content')) module.exports = WaterFall
-
新建note.js (src ==> js ==> mod == note.js)
require('less/note.less'); //拿到樣式 /* { id: ''; text: 'hello';} */ var Toast = require('./toast.js').Toast; var Event = require('mod/event.js'); function Note(opts){ this.initOpts(opts); this.createNote(); //創(chuàng)建便利貼 this.setStyle(); //設(shè)置樣式 this.bindEvent(); } Note.prototype = { colors: [ ['#ea9b35','#efb04e'], // headColor, containerColor ['#dd598b','#e672a2'], ['#eee34b','#f2eb67'], ['#c24226','#d15a39'], ['#c1c341','#d0d25c'], ['#3f78c3','#5591d2'] ], defaultOpts: { id: '', //Note的 id $ct: $('#content').length>0?$('#content'):$('body'), //默認(rèn)存放Note 的容器 context: 'input here' //Note 的內(nèi)容 }, initOpts: function (opts) { //默認(rèn)一個(gè)初始化乳蓄,設(shè)置id和參數(shù) this.opts = $.extend({}, this.defaultOpts, opts||{}); if(this.opts.id){ this.id = this.opts.id; } }, createNote: function () { var tpl = '<div class="note">' + '<div class="note-head"><span class="delete">×</span></div>' + '<div class="note-ct" contenteditable="true"></div>' +'</div>'; // 創(chuàng)建html咪橙,放到網(wǎng)頁上 // contenteditable 不是input,設(shè)置H5屬性虚倒,可以編輯 this.$note = $(tpl); this.$note.find('.note-ct').html(this.opts.context); this.opts.$ct.append(this.$note); if(!this.id) this.$note.css('bottom', '10px'); //新增放到右邊 }, setStyle: function () { var color = this.colors[Math.floor(Math.random()*6)]; this.$note.find('.note-head').css('background-color', color[0]); this.$note.find('.note-ct').css('background-color', color[1]); }, setLayout: function(){ var self = this; if(self.clk){ clearTimeout(self.clk); } self.clk = setTimeout(function(){ Event.fire('waterfall'); //發(fā)送一個(gè)瀑布流 },100); }, bindEvent: function () { var self = this, $note = this.$note, $noteHead = $note.find('.note-head'), $noteCt = $note.find('.note-ct'), $delete = $note.find('.delete'); $delete.on('click', function(){ self.delete(); //調(diào)用刪除 }) //contenteditable沒有 change 事件美侦,所有這里做了模擬通過判斷元素內(nèi)容變動,執(zhí)行 save $noteCt.on('focus', function() { if($noteCt.html()=='input here') $noteCt.html(''); $noteCt.data('before', $noteCt.html()); }).on('blur paste', function() { if( $noteCt.data('before') != $noteCt.html() ) { $noteCt.data('before',$noteCt.html()); self.setLayout(); if(self.id){ self.edit($noteCt.html()) }else{ self.add($noteCt.html()) } } }); //設(shè)置筆記的移動 $noteHead.on('mousedown', function(e){ // 當(dāng)鼠標(biāo)點(diǎn)下去的時(shí)候 var evtX = e.pageX - $note.offset().left, //evtX 計(jì)算事件的觸發(fā)點(diǎn)在 dialog內(nèi)部到 dialog 的左邊緣的距離 evtY = e.pageY - $note.offset().top; $note.addClass('draggable').data('evtPos', {x:evtX, y:evtY}); //把事件到 dialog 邊緣的距離保存下來 }).on('mouseup', function(){ // 鼠標(biāo)移開的時(shí)候魂奥,把class刪除掉 $note.removeClass('draggable').removeData('pos'); }); $('body').on('mousemove', function(e){ $('.draggable').length && $('.draggable').offset({ top: e.pageY-$('.draggable').data('evtPos').y, // 當(dāng)用戶鼠標(biāo)移動時(shí),根據(jù)鼠標(biāo)的位置和前面保存的距離,計(jì)算 dialog 的絕對位置 left: e.pageX-$('.draggable').data('evtPos').x }); }); }, edit: function (msg) { //當(dāng)需要編輯的時(shí)候 var self = this; $.post('/api/notes/edit',{ id: this.id, note: msg }).done(function(ret){ if(ret.status === 0){ Toast('update success'); }else{ Toast(ret.errorMsg); } }) }, add: function (msg){ console.log('addd...'); var self = this; $.post('/api/notes/add', {note: msg}) .done(function(ret){ if(ret.status === 0){ Toast('add success'); }else{ self.$note.remove(); Event.fire('waterfall') Toast(ret.errorMsg); } }); //todo }, delete: function(){ var self = this; $.post('/api/notes/delete', {id: this.id}) .done(function(ret){ if(ret.status === 0){ Toast('delete success'); self.$note.remove(); Event.fire('waterfall') }else{ Toast(ret.errorMsg); } }); } }; module.exports.Note = Note;
-
新建note-manager.js(src ==> js ==> mod == note-manager.js)
// 獲取數(shù)據(jù)歌懒,添加數(shù)據(jù) var Toast = require('./toast.js').Toast; var Note = require('./note.js').Note; var Toast = require('./toast.js').Toast; var Event = require('mod/event.js'); var NoteManager = (function(){ function load() { $.get('/api/notes') .done(function(ret){ if(ret.status == 0){ $.each(ret.data, function(idx, article) { new Note({ id: article.id, context: article.text }); }); Event.fire('waterfall'); }else{ Toast(ret.errorMsg); } }) .fail(function(){ Toast('網(wǎng)絡(luò)異常'); }); } function add(){ new Note(); } return { load: load, add: add //獲取數(shù)據(jù)茶袒,和添加 } })(); module.exports.NoteManager = NoteManager
-
修改index.js (src ==> js ==> app == index.js)
清空測試代碼,添加以下 require('less/index.less'); var NoteManager = require('mod/note-manager.js').NoteManager; var Event = require('mod/event.js'); var WaterFall = require('mod/waterfall.js'); NoteManager.load(); //加載所有的數(shù)據(jù) $('.add-note').on('click', function() { // 點(diǎn)擊添加按鈕哈蝇,調(diào)用添加 NoteManager.add(); }) Event.on('waterfall', function(){ //事件聽到waterfall的時(shí)候棺妓,執(zhí)行一次瀑布流 WaterFall.init($('#content')); })
添加index.less
-
約定接口
1.獲取所有的note: GET /api/notes req:{} res:{ status: 0, data:[{},{}]} {status: 1,errorMsg:'失敗的原因'} 2.創(chuàng)建一個(gè)note:POST: /api/notes/add req:{note: 'hello world'} res:{ status:0} {status: 1,errorMsg:'失敗的原因'} 3.修改一個(gè)note:POST:/api/notes/edit req:{note: 'new note',id:100} 4.刪除一個(gè)note:POST:/api/notes/detele req:{id:100} app.js 添加 app.use('/api',api) routes中api.js添加以上接口 router.get('/notes', function(req, res, next) { console.log('/notes') }); router.post('/notes/add', function(req, res, next) { var note = req.body.note; console.log('add...') }); router.post('/notes/edit', function(req, res, next) { }); router.post('/notes/delete', function(req, res, next) { });
-
數(shù)據(jù)庫
SQL 教程
npm mysql
sequelize
sequelize文檔 V3
npm install --save sequelize
npm install --save sqlite3 如果node-v48-win32-x64.tar.gz卡住了,賦值url炮赦,fq下載怜跑, 替換到node_modules/sqlite3/lib/binding 里面的 node-v48-linux-x64
使用sequelize var Sequelize = require('sequelize'); var sequelize = new Sequelize('database', 'username', 'password'); // 連接數(shù)據(jù)庫 //定義一個(gè)表,就是一個(gè)模型吠勘,對應(yīng)數(shù)據(jù)庫里一個(gè)表 var User = sequelize.define('user', { // 對應(yīng)數(shù)據(jù)庫里性芬,user表 username: Sequelize.STRING, //string birthday: Sequelize.DATE //date }); sequelize.sync().then(function() { //創(chuàng)建這個(gè)表 return User.create({ //創(chuàng)建一個(gè)數(shù)據(jù) username: 'janedoe', birthday: new Date(1980, 6, 20) }); }).then(function(jane) { console.log(jane.get({ plain: true })); });
-
node端如何調(diào)試
npm install -g node-inspector 安裝調(diào)試工具 node-inspector 啟動調(diào)試軟件(默認(rèn)占用8080端口) // 注意提示調(diào)試網(wǎng)址峡眶,通過該網(wǎng)址進(jìn)行調(diào)試 還需要開啟服務(wù)器 node --debug bin/www 刷新服務(wù)器網(wǎng)址,再刷新調(diào)試網(wǎng)站即可植锉。
-
檢測數(shù)據(jù)能否使用
在項(xiàng)目目錄下新建model ==> note.js var sequelize = new Sequelize(undefined, undefined, undefined, { //不需要用戶名密碼辫樱,如果是其他數(shù)據(jù)庫需要做義工配置 host: 'localhost', dialect: 'sqlite', storage: '../database/database.sqlite' }); //測試是否成功,使用完成就可注釋掉 sequelize .authenticate() .then(function(err){ console.log('Connection has been established successfully.'); }) .catch(function(err){ console.log('Unable to connect to the database:',err); }) routes ==》 aip.js var Note = require('../model/note') router.get('/notes', function(req, res, next) { var data = Note.getAll() //模型汽煮,用于具體的和數(shù)據(jù)進(jìn)行操作搏熄。 //假設(shè)有個(gè)對象叫Note,有g(shù)etAll方法暇赤,把他所有數(shù)據(jù)賦值給data res.send({status: 0, data: notes}) }); cd model node note.js 會在database文件夾下生成空的database.sqlite
-
向數(shù)據(jù)庫添加數(shù)據(jù)
note.js添加數(shù)據(jù)心例,創(chuàng)建模型,一個(gè)模型鞋囊,對應(yīng)數(shù)據(jù)庫的一個(gè)表 // id [字段] [添加時(shí)間] [更新時(shí)間] //模型起名叫note var Note = sequelize.define('note', { text: { type: Sequelize.STRING //向數(shù)組添加字段止后,類型為string,會默認(rèn)添加id 添加時(shí)間 更新時(shí)間 } }); //sync({force: true}) 假設(shè)數(shù)據(jù)庫存在這個(gè)表溜腐,force:true刪除译株。 Note.sync().then(function(){ Note.create({text:'hello world'}) }).then(function(){ Note.findAll().then(function (notes) { //findOne({raw: true}) 獲取里面的數(shù)據(jù) console.log(notes); }) }) //添加完成后注釋 cd model 運(yùn)行 node note.js Note.findOne({raw: true, where:{id:2}}).then(function(notes){ console.log(notes) }) //findOne({raw: true}) 獲取里面的數(shù)據(jù),如果不加,會把所有數(shù)據(jù)展示 // 會輸出 id 為 2 的數(shù)據(jù)挺益。
-
api.js中的數(shù)據(jù)增刪改查
router.post('/notes/add', function(req, res, next) { if(!req.session || !req.session.user){ return res.send({status: 1, errorMsg: '請先登錄'}) } var uid = req.session.user.id var note = req.body.note; Note.create({text: note, uid: uid}).then(function(){ res.send({status: 0}) //status: 0 成功 }).catch(function(){ res.send({status: 1,errorMsg: '數(shù)據(jù)庫出錯(cuò)'}) //status: 1 出錯(cuò) }) console.log('add...',note) }) router.post('/notes/edit', function(req, res, next) { if(!req.session || !req.session.user){ return res.send({status: 1, errorMsg: '請先登錄'}) } var uid = req.session.user.id Note.update({text: req.body.note},{where:{id:req.body.id,uid:uid}}).then(function(){ console.log(arguments) res.send({status:0}) }).catch(function(){ res.send({status: 1,errorMsg: '數(shù)據(jù)庫出錯(cuò)'}) //status: 1 出錯(cuò) }) }); router.post('/notes/delete', function(req, res, next) { if(!req.session || !req.session.user){ return res.send({status: 1, errorMsg: '請先登錄'}) } var uid = req.session.user.id Note.destroy({where:{id:req.body.id,uid:uid}}).then(function(){ res.send({status:0}) }).catch(function(){ res.send({status: 1,errorMsg: '數(shù)據(jù)庫出錯(cuò)'}) //status: 1 出錯(cuò) }) });
-
修改路徑
使用更穩(wěn)定的路徑方式 model ==》 note.js var path = require('path') //添加到頁面 storage: path.join(__dirname,'../database/database.sqlite') //修改頁面代碼 module.exports.Note = Note; //導(dǎo)出,提供給其外部使用 routes ==> api.js var Note = require('../model/note').Note; //修改代碼歉糜,引用note.js
-
登錄功能
阮一峰 oauth 2.0文章
oauth 2是一個(gè)認(rèn)證協(xié)議。當(dāng)點(diǎn)擊第三方登錄的時(shí)候望众,跳轉(zhuǎn)到第三方網(wǎng)站匪补,登錄成功后,返回當(dāng)前頁面烂翰。中間oauth2.0做一個(gè)支撐夯缺。(點(diǎn)擊登錄,向后臺發(fā)起請求甘耿,后臺向第三方接口請求踊兜,登錄成功,網(wǎng)站后臺拿到一個(gè)key佳恬,返回頁面捏境。)- app.js增加第三方登錄接口
var auth = require('./routes/auth'); app.use('/auth', auth);
- 增加auth路由
routes ==> 新建auth.js
- 使用passport,第三方登錄
npm passport
npm install passport
passport-github
npm install passport-github
GitHub申請第三方登錄授權(quán)殿怜。https://github.com/settings/ - app.js 添加session中間鍵
npm install express-session
var passport = require('passport'); var session = require('express-session'); app.use(session({secret: '[隨便寫一串字符串典蝌,作為一個(gè)秘鑰]'})); app.use(passport.initialize()); app.use(passport.session());
cookie 和 session的關(guān)系
http是一個(gè)無狀態(tài)的協(xié)議,每次請求不知道是誰發(fā)的請求头谜,只知道有一個(gè)請求url過來骏掀,需要做什么事情。
需求:用戶登錄了之后,刷新了頁面截驮,下次還是登錄狀態(tài)笑陈。需要記錄用戶的狀態(tài)。
這個(gè)時(shí)候葵袭,需要使用cookie和session涵妥,當(dāng)使用用戶名和密碼提交給后臺的時(shí)候,后臺會從數(shù)據(jù)庫里面查詢坡锡,(一般密碼都不是明文蓬网,都是經(jīng)過MD5和SHA1加密的,會把密碼從新進(jìn)行一次加密鹉勒。)帆锋,加密好了之后,從數(shù)據(jù)庫查詢用戶名禽额,得到之后锯厢,再把加密后的密碼進(jìn)行匹配。如果匹配上了脯倒,就表示登錄上了实辑,表示登錄上了也沒用,所有需要記錄登錄狀態(tài)藻丢,把用戶的信息剪撬,再服務(wù)器里面創(chuàng)建一個(gè)session,一個(gè)session可以認(rèn)為是一個(gè)數(shù)據(jù)對象悠反,在內(nèi)存里面婿奔,session有一個(gè)key,key對應(yīng)的value就是session问慎,session可以存儲在任何地方,默認(rèn)存在內(nèi)存里挤茄,沒有把他存在某個(gè)地方如叼,是一個(gè)變量,存在服務(wù)器內(nèi)存穷劈,key就是一串很長的數(shù)值笼恰。
用戶請求過來,向用戶展示頁面歇终,在服務(wù)器通過send cookie,相當(dāng)于http請求社证,當(dāng)用戶打開頁面的時(shí)候,發(fā)現(xiàn)http的請求里面评凝,有一個(gè)叫cookie,會把key存到cookie里面追葡,里面的文件connect.sid傳字符串。
在刷新頁面,就會把所有請求都帶上宜肉,同時(shí)cookie也發(fā)到服務(wù)器里面匀钧,服務(wù)器就通過這個(gè)cookie,就從剛才的數(shù)據(jù)內(nèi)存里面去查找谬返,得到這個(gè)對象之斯,然后得到這個(gè)用戶,展示和這個(gè)用戶相關(guān)的信息遣铝。
session是服務(wù)端的對象佑刷,有個(gè)key,把key發(fā)給瀏覽器酿炸,瀏覽器記錄下來瘫絮,這就是cookie。-
添加登錄注銷效果
- index.ejs
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta property="qc:admins" content="4562636714562571563145" /> <title><%= title %></title> <link rel="stylesheet" href="/css/index.css"> </head> <body> <div id="header"> <a class="add-note" title="添加筆記" href="#"><span class="fa fa-plus"></span> 添加</a> <ul class="user-area"> <% if (isLogin){ %> <li><img src="<%= user.avatar %>" alt=""></li> <li><span title="<%= user.username %>"><%= user.username %></span></li> <li><span class="line"> | </span> </li> <li><a class="logout" href="/auth/logout">注銷</a></li> <%} else { %> <li><a class="login" title="GitHub登錄" href="/auth/github"> GitHub登錄</a> </li> <% } %> </ul> </div> <div id="content"> </div> <div class="stars"></div> <script src="/js/index.js"></script> <!-- <div class="twinkling"></div> --> </body> </html>
- index.js
var express = require('express'); var router = express.Router(); /* GET home page. */ router.get('/', function(req, res, next) { res.render('index', { title: '我的便利貼' }); }); router.get('/', function(req, res, next) { var data; if(req.session.user){ data = { isLogin: true, user: req.session.user } }else{ data = { isLogin: false } } console.log(data) res.render('index', data); }); module.exports = router;
- auth.js
var express = require('express'); var router = express.Router(); var passport = require('passport'); //引入passport梁沧,專門負(fù)責(zé)auth2的認(rèn)證檀何,所有的第三方登錄,都可以使用passport var GitHubStrategy = require('passport-github').Strategy; //在passport基礎(chǔ)上廷支,對整個(gè)協(xié)議進(jìn)行的封裝频鉴。 passport.serializeUser(function(user, done) { console.log('---serializeUser---') console.log(user) done(null, user); }); //把用戶登陸過來的信息,傳遞到passport之后恋拍,讓它生成一個(gè)session垛孔,存儲到內(nèi)存里面 passport.deserializeUser(function(obj, done) { console.log('---deserializeUser---') done(null, obj); }); // 用戶刷新頁面的時(shí)候,會再從內(nèi)存里面施敢,把對應(yīng)的session拿出來周荐,解析,知道這個(gè)用戶 passport.use(new GitHubStrategy({ clientID: '28928eae8774e53d2247', clientSecret: '0485fe61b10dac188ff17d977253ba091113f94d', callbackURL: "http://127.0.0.1:3000/auth/github/callback" }, function(accessToken, refreshToken, profile, done) { // User.findOrCreate({ githubId: profile.id }, function (err, user) { // }); done(null, profile); } )); //入口 router.get('/github', passport.authenticate('github')); router.get('/github/callback', passport.authenticate('github', { failureRedirect: '/login' }), function(req, res) { req.session.user = { id: req.user.id, username: req.user.displayName || req.user.username, avatar: req.user._json.avatar_url, provider: req.user.provider }; res.redirect('/'); }); //注銷 router.get('/logout',function(req,res){ req.session.destroy() //銷毀session res.redirect('/') //跳轉(zhuǎn)到首頁 }) module.exports = router;
npm start 開啟本地服務(wù)器