㈠ node怎麼設置session
以下內容來自網路:
node.js 是有windows實現版本的,請到它的官網node.org下載。有兩種 exe和msi都可以使用。
下載後安裝和正常軟體安裝一樣。使用方法:
在開始菜單打開,選擇 Node.js command prompt ,它自動幫你加入了環境變數,直接可以使用 node 和npm命令。
node命令: node (空格)js程序,請用絕對地址。其他參數可以用node -h查看,有詳細的解釋
npm命令:npm是node安裝第三方模塊的命令,使用非常簡單npm install 模塊名即可。其他參數可以可以使用npm -h 查看
這里npm的模塊都必須在npm.org上注冊使用。
另外在提供一個中文社區 cnodejs.org不錯的中文社區。也提供中文文檔。
還有一點關於平台選擇,其實並不是linux好,node的核心事件驅動機制在linux使用的是模擬的libev+libeio庫模擬的,而windows則本身就提供了系統調用,性能據測試過的人數據是windows佔大優勢的。當然這並不影響你在windows和linux使用node.js,他是完全跨平台的!
㈡ 如何給nodejs redis session 定時
這里所說的定時任務可以說是計時器任務,比如說用戶觸發了某個動作,那麼從這個點開始過二十四小時要對這個動作做點什麼。那麼如果有 1000 個用戶觸發了這個動作,就會有 1000 個定時任務。於是這就不是 Cron 范疇裡面的內容了。
舉個最簡單的例子,一個用戶推薦了另一個用戶,定一個二十四小時之後的任務,看看被推薦的用戶有沒有來注冊,如果沒注冊就給他搞一條簡訊過去。Σ>―(〃°ω°〃)♡→
最初的設想
一開始是想把這個計時器做在內存裡面直接調用的。
考慮到 Node.js 的定時並不是那麼准確(無論是setTimeout還是setInterval),所以本來打算自己維護這個定時器隊列。
又考慮到 Node.js 原生對象比較耗內存。之前用JSON對象存了一本字典,約十二萬多的詞條,原文件大概也就五六兆,用 Node.js 的原生對象一存居然有五六百兆的內存佔用——所以打算這個定時器隊列用 C++ 來寫 addon。
考慮到任何時候插入的任務都有可能在已有的任務之前或者之後,所以本來想用 C++ 來寫一個 小根堆 。每次用戶來一個任務的時候就將這個任務插入到堆中。
如果按照上述方法的話,再加上對時間要求掐得也不是那麼緊,於是就是一個不斷的process.nextTick()的過程。
在process.nextTick()當中執行這么一個函數:
從小根堆中不斷獲取堆頂的任務並處理,一直處理到堆頂任務的執行時間大於當前時間為止。
繼續process.nextTick()來讓下一個 tick 執行步驟 1 中的流程。
所以最後就是一邊往小根堆插入任務,另一邊通過不斷process.nextTick()消費任務的這么一個過程。
最後,為了考慮到程序重啟的時候內存數據會丟失,還應該做一個持久化的事情——在每次插入任務的時候順便往持久化中間件中插一條副本,比如 MySQL、MongoDB、Redis、Riak 等等任何三方依賴。消費任務的時候順便把中間件中的這條任務數據給刪除。
也就是說中間件中永遠存的就是當前尚未完成的任務。每當程序重啟的時候都先從中間件中把所有任務讀取進來重建一下堆,然後就能繼續工作了。
如果當時沒有發現 Redis 的這個妙用的話,上述的流程將會是實現定時任務的流程了。
Redis 妙用
在 Redis 的 2.8.0 版本之後,其推出了一個新的特性——鍵空間消息( Redis Keyspace Notifications ),它配合 2.0.0 版本之後的SUBSCRIBE就能完成這個定時任務的操作了, 不過定時的單位是秒 。
Publish / Subscribe
Redis 在 2.0.0 之後推出了 Pub / Sub 的指令,大致就是說一邊給 Redis 的特定頻道發送消息,另一邊從 Redis 的特定頻道取值——形成了一個簡易的消息隊列
比如可以往foo頻道推一個消息bar,那麼就可以直接:
PUBLISH foo bar
javascript
var Redis = require("ioredis");
var sub = new Redis(/** 連接信息 */);
sub.once("connect", function() {
// 假設需要選擇 redis 的 db,因為實際上們不會去污染默認的 db 0
sub.select(DB_NUMBER, function(err) {
if(err) process.exit(4);
sub.subscribe("foo", function() {
//... 訂閱頻道成功
});
});
});
// 監聽從 `foo` 來的消息
sub.on("message", function(channel, msg) {
console.log(channel, msg);
});
Redis Keyspace Notifications
在 Redis 裡面有一些事件,比如鍵到期、鍵被刪除等。然後可以通過配置一些東西來讓 Redis 一旦觸發這些事件的時候就往特定的 Channel 推一條消息。
本文所涉及到的需求的話所需要關心的事件是EXPIRE即過期事件。
大致的流程就是給 Redis 的某一個 db 設置過期事件,使其鍵一旦過期就會往特定頻道推消息,在自己的客戶端這邊就一直消費這個頻道就好了。
以後一來一條定時任務,就把這個任務狀態壓縮成一個鍵,並且過期時間為距這個任務執行的時間差。那麼當鍵一旦到期,就到了任務該執行的時間,Redis 自然會把過期消息推去,的客戶端就能接收到了。這樣一來就起到了定時任務的作用。
消息類型
當達到一定條件後,有兩種類型的這種消息會被觸發,用哪個需要自己選了。舉個例子,刪除了在 db 0 中一個叫foo的鍵,那麼系統會往兩個頻道推消息,一個是del事件頻道推foo消息,另一個是foo頻道推del消息,它們小倆口被系統推送的指令分別等價於:
PUBLISH __keyspace@0__:foo del PUBLISH __keyevent@0__:del foo
其中往foo推送del的頻道名為__keyspace@0__:foo,即是"__keyspace@" + DB_NUMBER + "__:" + KEY_NAME;而del的頻道名為"__keyevent@" + DB_NUMBER + "__:" + EVENT_NAME。
配置
即使你的 Redis 版本達標了,但是 Redis 默認是關閉這個功能的,你需要修改配置文件來打開它,或者直接在 CLI 裡面通過指令修改。這里就說說配置文件的修改吧。。
首先打開 Redis 的配置文件,在不同的系統和安裝方式下文件位置可能不同,比如通過brew安裝的 MacOS 下可能是在/usr/local/etc/redis.conf下面,通過apt-get安裝的 Ubuntu 下可能是在/etc/redis/redis.conf下,總之找到配置文件。或者自己寫一個配置文件,啟動的時候指定配置文件地址就好。
然後找到一項叫notify-keyspace-events的地方,如果找不到則自行添加,其值可以是Ex、Klg等等。這些字母的具體含義如下所示:
K ,表示keyspace事件,有這個字母表示會往__keyspace@<db>__頻道推消息。
E ,表示keyevent事件,有這個字母表示會往__keyevent@<db>__頻道推消息。
g ,表示一些通用指令事件支持,如DEL、EXPIRE、RENAME等等。
$ ,表示字元串(String)相關指令的事件支持。
l ,表示列表(List)相關指令事件支持。
s ,表示集合(Set)相關指令事件支持。
h ,哈希(Hash)相關指令事件支持。
z ,有序集(Sorted Set)相關指令事件支持。
x ,過期事件,與 g 中的EXPIRE不同的是, g 的EXPIRE是指執行EXPIRE key ttl這條指令的時候順便觸發的事件,而這里是指那個key剛好過期的這個時間點觸發的事件。
e ,驅逐事件,一個key由於內存上限而被驅逐的時候會觸發的事件。
A ,g$lshzxe的別名。也就是說AKE的意思就代表了所有的事件。
結合上述列表就能拼湊出自己所需要的事件支持字元串了,在需求中只需要Ex就可以滿足了,所以配置項就是這樣的:
notify-keyspace-events Ex
然後保存配置文件,啟動 Redis 就啟用了過期事件的支持了。
實踐
先說任務的創造者吧。由於這里 Redis 的事件只會傳鍵名,並不會傳鍵值,而過期事件觸發的時候那個鍵已經沒了,你也無法獲取鍵值,加上主系統和任務系統是分布式的,所以就把所有需要的信息往鍵名塞。
一個最簡單的鍵名設計就是任務類型 + ":" + JSON.stringify 化後的參數數組;更有甚者可以直接把任務類型替換成所需的函數路徑,比如需要執行這個任務的函數在task/foo/bar文件下面的baz函數,參數arguments數組為[ 1, 2 ],那麼鍵名的設計可以是task/foo/bar.baz:[1,2],反正只需要觸發這個鍵,用不著去查詢這個鍵。等到真正過期了任務系統接收到這個鍵名的時候再一一解析,得到需要執行task/foo/bar.baz這個消息,並且網函數裡面傳入[1,2]這個arguments。
所以當接收到一個定時任務的時候,得到消息、函數名、過期時間參數,這個函數
/** 假設 redis 是一個 ioredis 的對象 */
var sampleTaskMaker = function(message, func, timeout) {
message = JSON.stringify(message);
console.log("Received a new task:", func, message, "after " + timeout + ".");
// 這里的 uuid 是 npm 一個包
// 生成一個唯一 uuid 的目的是為了防止兩個任務用了相同的函數和參數,那麼
// 鍵名可能會重復並覆蓋的情況
// uuid 的文檔為 https://www.npmjs.com/package/node-uuid
//
// 這里的 ❤️ 是一個分隔符,冒號是分割 uuid 和後面內容的,而 ❤️ 是分割函數名
// 和消息的
var key = uuid.v1().replace(/-/g, "") +
":❤️" + func + "❤️" + message;
var content = "";
redis.multi()
.set(key, content)
.expire(key, timeout)
.exec(function(err) {
if(err) {
console.error("Failed to publish EXPIRE EVENT for " + content);
console.error(err);
return;
}
});
};
// assign 是 sugarjs 裡面的函數
// 把 db 塞到字元串裡面的 {db} 里去
var subscribeKey = "__keyevent@{db}__:expired".assign({ db: 1 });
// 假設 sub 是 ioredis 的對象
sub.once("connect", function() {
// 假設需要選擇 redis 的 db,因為實際上不會去污染默認的 db 0
sub.select(1, function(err) {
if(err) process.exit(4);
sub.subscribe("foo", function() {
//... 訂閱頻道成功
});
});
});
// 監聽從 `foo` 來的消息
sub.on("message", sampleOnExpired);
注意:這里選擇 db 1 是因為一旦開啟過期事件監聽,那麼這個 db 的所有過期事件都會被發送。為了不跟正常使用的 redis 過期鍵混淆,為這個事情專門用一個新的 db。比如在自己正常使用的 db 0 裡面監聽了,那麼不是任務觸發的過期事件也會傳過來,這個時候解析的鍵名就不對了。
最後就是sampleOnExpired函數了。
var sampleOnExpired = function(channel, key) {
// UUID:❤️func❤️params
var body = key.split("❤️");
if(body.length < 3) return;
// 取出 body 第一位為 func
var func = body[1];
// 推出前兩位,後面剩下的有可能是參數裡面自帶 ❤️ 而被分割,所以要拼回去
body.shift(); body.shift();
var params = body.join("❤️");
// 然後把 params 傳入 func 去執行
// func:
// path1/path2.func
func = func.split(".");
if(func.length !== 2) {
console.error("Bad params for task:", func.join("."), "-", params);
return;
}
var path = func[0];
func = func[1];
var mod;
try {
mod = require("./tasks/" + path);
} catch(e) {
console.error("Failed to load mole", path);
console.error(e.stack);
return;
}
process.nextTick(function() {
try {
mod[func].apply(null, JSON.parse(params));
} catch(e) {
console.error("Failed to call function", path, "-", func, "-", params);
console.error(e.stack);
}
});
};
這個簡易的架子搭好後,只需要去寫一堆任務執行函數,然後在生成任務的時候把相應參數傳給sampleTaskMaker就好了。Redis 會自動過期並且觸發事件給sampleOnExpired函數,然後就會去執行相應的任務處理函數了
㈢ nodejs function 裡面怎麼用session
如果樓主所說的session丟失是指存在cookie中的session-id沒有帶上,樓主可以去看看xhr的withCredentials。
㈣ 怎麼學習nodejs websocket
NodeJS貌似在一直升溫。的確,從去年就一直開始關注NodeJS了,那個時候還是吳璽喆同學和我談起這個事情~~~回頭我就算變掃了一下,無非就是在伺服器端運行的JS而已。使用JavaScript作為指令調用底層的C++,這個思維模式還是挺不錯的,並且在伺服器端執行的效果也非常理想。那個時候想養肥了再看看,結果不到半年時間NodeJs已經有了飛速的發展,各方面的組件,各方面的社區文章介紹都已經非常全面了。NodeJS並且已經退出了Windows版本的安裝程序。極大的方便了開發者(之前是在Ubuntu環境下部署的)。
webSocket 是一個非常不錯特性,與其說是Html5的功能,不如說是瀏覽器支持的功能。Html5隻是一個規范草案,添加了canvas,header,footer,nav,silder等一系列更加優化的語義標簽,而Geolocation,webSocket,localStore等都是瀏覽器廠商支持的結果。(概念不要混淆哦)正好趁著去學習的時間,做了一個NodeJS與webSocket的小例子。拿出來和各位共享一下。
webSocket 是 Html5 的一種新的協議。它實現了瀏覽器與伺服器的雙向通訊。webSocket API 中,瀏覽器和伺服器端只需要通過一個握手的動作,便能形成瀏覽器與客戶端之間的快速雙向通道,使得數據可以快速的雙向傳播。
通過一次簡單的握手,建立了客戶端和伺服器端的聯系之後,伺服器便可以主動推送信息給客戶端,而不需要客戶端的反復輪詢請求。在之前已經有谷歌的工程師嘗試使用iframe來實現次功能,具體細節這里就不談了,請各位自行谷歌。
webSocket 伺服器商用已經很多了,這里不用 php,java 而是使用最近熱得發燙的 NodeJs 來作為案例解析。
安裝了NodeJS之後,我們可以通過一行簡單的插件命令來安裝 socket 模塊。
npm install socket
然後引入包和啟動伺服器代碼。
var http = require('http'),
io = require('socket.io'),
fs = require('fs');
//配置
var config = {
port : 8888
}
//創建伺服器,監聽埠。
http = http.createServer(handler);
http.listen(config.port);
//創建webscoket監聽伺服器
io = io.listen(http);
function handler(req, res) {
fs.readFile(__dirname+'/client.html',
function(err, data){
req.setEncoding(encoding="utf8");
res.writeHead(200);
res.end(data);
});
}
io.sockets.on('connection',function(socket){
//定義事件
socket.on('msg',function(data){
socket.broadcast.emit('user message',data);
});
});
然後我們來編寫我們的客戶端
<script src="http://192.168.39.154:8888/socket.io/socket.io.js"></script>
<script type="text/javascript">
var socket = io.connect('http://192.168.39.154:8888/');
//Comet
socket.on('user message', function(msg) {
msgbox(msg.msg);
});
//發送消息
function sendMsg() {
var inpt = document.getElementById('txtInput');
var str = inpt.value;
if(str.length==0){
inpt.className="error";
alert("請輸入發送的消息內容");
return false;
}
inpt.className = "";
msgbox(str);
//發送消息至伺服器的Scoket。
socket.emit('msg', {
msg : str
});
console.log('[client]' + str);
inpt.value = "";
inpt.focus();
}
以上就是核心源代碼。
㈤ nodejs從session里拿用戶名
首先,你需要在伺服器端使用一個Session模塊,比如Express的Session模塊。
然後,在你的路由中,你可以訪問req.session.username,這樣就可以獲取到用戶名了。
例如:
app.get('/', function(req, res){
var username = req.session.username;
res.send('Hello ' + username);
});
㈥ 為什麼nodejs里session沒有secret配置項就會報錯
secret 是必需的選項,這是用於簽名會話ID cookie的密鑰。這可以是單個密鑰的字元串或專多個秘密的數組。如果屬提供了一組密鑰,只有第一個元素將用於簽名會話ID cookie,而在驗證請求中的簽名時,將考慮所有元素。參考:https://github.com/expressjs/session
㈦ NodeJs中的cookie、Session-cookie
首次請求服務端會在響應的 headers 里邊種下 Cookie ,再次請求服務,瀏覽器就會帶上 Cookie ,
然後這樣會存在一些問題,首先 Cookie 不能存太大,設置在瀏覽器端可以看到可以被修改,不是那麼的安全。
正因為 Cookie 的弊端,所以我們能不能把重要信息保存在伺服器, Cookie 中值保留簡單的一個ID將來用於去伺服器獲取對應信息
那麼接下來看下 Koa 中如何使用 Session-cookie 模式
當 httpOnly 設置為 true 的時候cookie ygc:sess 在瀏覽器中是無法讀取的;
當 signed 設置為 true 的時候,會成對的出現 ygc:sess.sig ,它是 app.keys 和 ygc:sess 哈希的結果;防止被篡改;
哈希會滿足幾個條件 把不定長轉換成定長,摘要,雪崩效應;
以上session放在本地,多個實例不能共享
㈧ node express session怎麼用
1:存儲到內存中
var session = require('express-session');
app.use(session({
secret: configs.sysconfig.sessionsecret,
key: configs.sysconfig.sessionsid,
cookie: {
secret: true,
expires: false
},
resave: true,
saveUninitialized: true
}));
2:存儲到redis
app.use(session({
store: new RedisStore({
host: "127.0.0.1",
port: 6379,
db: "test_session"
}),
resave:false,
saveUninitialized:false,
secret: 'keyboard cat'
}))
3:存儲到mongodb
app.use(session({
secret: config.session_opts.sessionsecret,
store: new MongoStore({
url: config.session_opts.db
}),
resave: true,
saveUninitialized: true
}));
㈨ 解決vue nodejs中cros跨域cookie和session失效的問題
很多童鞋會發現vue請求api介面的時候多個地址沒法共享session,也就是session會丟失。我們知道session是基於cookie的,ajax請求沒法共享session主要是因為cookie跨域引起的。cookie跨域如何解決呢?
㈩ PHP 與 NodeJS 如何共用 Session
PHP 與 NodeJS共用 Session的方法是PHP暴露一個Service,向Node提供Session數據。php_session.php?SID=xxxx
1、php代碼:
<?php
function getSessionByID($SID) {
if (session_id()) {
// 關閉當前session
session_destroy();
}
// 初始化指定session
session_id($SID);
session_start();
// 返回操作介面更友好的JSON
// 必要的FLAG看這里 http://www.php.net/manual/en/json.constants.php
return json_encode($_SESSION);
}
header('Content-Type:application/json');
echo getSessionByID($_GET['SID']);
?>
2、node實現代碼:
var request = require('request');
request('http://localhost/php_session.php?SID=xxxx', function(err, res, body) {
if (!err && res.statusCode == 200) {
// 根據需要使用body(json)
}
});