url
主要是配置一系列和路徑相關的信息url.parse(urlString[, parseQueryString[, slashesDenoteHost]]) 將一個URL字符串解析爲URL對象 urlString: 解析的路徑字符串 parseQueryString: 返回是布爾類型,主要用來解析query的 slashesDenoteHost: 返回是布爾類型,當你不肯定你的請求協議時,輔助幫助你進行解析 url.format(urlObj,parseObj,slashesObj) 將url對象轉換爲字符串 與parse參數相反 url.resolve(from, to) 將基礎路徑和後綴路徑轉換成目標路徑 from 解析時相對的基本URL to 要解析的超連接 URL 值得注意的是基本路徑要在路徑最後添加'/',不然合併會找到你最近的'/'並替換 const url = require('url'); url.resolve('/one/two/three', 'four'); // '/one/two/four' url.resolve('http://example.com/', '/one'); // 'http://example.com/one' url.resolve('http://example.com/one', '/two'); // 'http://example.com/two'
queryString
爲查詢字符串提供擴展querystring 模塊提供了一些實用函數,用於解析與格式化 URL 查詢字符串 querystring.parse(str,con,seq) str 要解析的 URL 查詢字符串 con用於界定查詢字符串中的鍵值對的子字符串。默認爲 '&' seq 用於界定查詢字符串中的鍵與值的子字符串。默認爲 '=' querystring.stringify(obj,con,seq) obj 要序列化成 URL 查詢字符串的對象 con 用於界定查詢字符串中的鍵值對的子字符串。默認爲 '&' seq 用於界定查詢字符串中的鍵與值的子字符串。默認爲 '=' querystring.escape(str) 至關於encodeURI 將Asc編碼轉換成utf-8 對給定的str進行 URL編碼 該方法是提供給 querystring.stringify()使用的,一般不直接使用 querystring.unescape(str) 至關於decodeURI 將utf-8轉換成ASc 對給定的str進行解碼 該方法是提供給 querystring.parse()使用的,一般不直接使用
大多數 Node.js 核心 API 構建於慣用的異步事件驅動架構,其中某些類型的對象(又稱觸發器,Emitter)會觸發命名事件來調用函數(又稱監聽器,Listener)javascript
當 EventEmitter 對象觸發一個事件時,全部綁定在該事件上的函數都會被同步地調用html
例子,一個簡單的 EventEmitter 實例,綁定了一個監聽器。 eventEmitter.on() 方法用於註冊監聽器,eventEmitter.emit() 方法用於觸發事件。vue
const Eventemitter = require("events") class Player extends Eventemitter {} const player = new Player() //使用 eventEmitter.on() 註冊監聽器時,監聽器會在每次觸發命名事件時被調用 player.on("change",(track) => { console.log(`node事件機制`,${track}) }) //使用 eventEmitter.once() 能夠註冊最多可調用一次的監聽器。 當事件被觸發時,監聽器會被註銷,而後再調用 //player.once("change",(track) => { // console.log(`node事件機制`,${track}) //}) player.emit("change","react") player.emit("change","vue")
傳參數與this到監聽器
eventEmitter.emit() 方法能夠傳任意數量的參數到監聽器函數。 當監聽器函數被調用時,this 關鍵詞會被指向監聽器所綁定的 EventEmitter 實例java
const myEmitter = new MyEmitter(); myEmitter.on('event', function(a, b) { console.log(a, b, this, this === myEmitter); // 打印: // a b MyEmitter { // domain: null, // _events: { event: [Function] }, // _eventsCount: 1, // _maxListeners: undefined } true }); myEmitter.emit('event', 'a', 'b');
emitter.removeAllListeners([eventName])
移除所有監聽器或指定的 eventName 事件的監聽器。node
fs 模塊提供了一些接口用於以一種相似標準 POSIX 函數的方式與文件系統進行交互react
全部的文件系統操做都有同步和異步兩種形式git
異步形式的最後一個參數都是完成時的回調函數。 傳給回調函數的參數取決於具體方法,但回調函數的第一個參數都會保留給異常。 若是操做成功完成,則第一個參數會是 null 或 undefinedgithub
fs.Stats
類
fs.Stats 對象提供了一個文件的信息
stats.isDirectory() 若是 fs.Stats 對象表示一個文件系統目錄,則返回 true
stats.isFile() 若是 fs.Stats 對象表示一個普通文件,則返回 truemongodb
fs.mkdir(path[, options], callback)
異步地建立目錄。 完成回調只有一個可能的異常參數數據庫
// 建立 /temp/a/apple 目錄,無論 `/temp` 和 /temp/a 目錄是否存在。 fs.mkdir('/temp/a/apple', (err) => { if (err) throw err; });
fs.writeFile(file, data[, options], callback)
異步地寫入數據到文件,若是文件已經存在,則覆蓋文件。 data 能夠是字符串或 buffer
fs.writeFile('temp.js', 'keep study', (err) => { if (err) throw err; console.log('文件已保存!'); });
fs.appendFile(path, data[, options], callback)
異步地追加數據到文件,若是文件不存在則建立文件。 data 能夠是字符串或 Buffer
fs.appendFile('temp.js', '追加的數據', (err) => { if (err) throw err; console.log('數據已追加到文件'); });
fs.readFile(path[, options], callback)
異步地讀取一個文件的所有內容
fs.readFile('/etc/passwd', (err, data) => { if (err) throw err; console.log(data); });
回調有兩個參數 (err, data),其中 data 是文件的內容。
若是未指定字符編碼,則返回原始的 buffer。
若是 options 是一個字符串,則它指定了字符編碼。例子:
fs.readFile('/etc/passwd', 'utf8', callback);
fs.readdir(path[, options], callback)
讀取目錄的內容。 回調有兩個參數 (err, files),其中 files 是目錄中文件名的數組,不包含 '.' 和 '..'。
options 參數用於傳入回調的文件名。 它能夠是一個字符串,指定字符編碼。 也能夠是一個對象,其中 encoding 屬性指定字符編碼。 若是 encoding 設爲 'buffer',則返回的文件名會是 Buffer 對象。
fs.rmdir(path, callback)
刪除目錄
fs.readFileSync(path[, options])
同步讀取文件
fs.readdirSync(path[, options])
同步讀取目錄
fs.unlink(path, callback)
解除關係(也即刪除文件)
readFileSync和unlink結合實現刪除一個目錄及其目錄下的文件的例子:
const fs = require('fs'); fs.readdirSync("logs").map((file) => { fs.unlink(`logs/${file}`,() => { console.log("刪除成功") }) }) fs.rmdir("logs", (err)=> { console.log("肯定要刪除嗎?") })
fs.watch(filename[, options][, listener])
監視 filename 的變化,filename 能夠是一個文件或一個目錄。
若是提供的 options 是一個字符串,則它指定了 encoding。 不然 options 應該傳入一個對象。
監聽器回調有兩個參數 (eventType, filename)。 eventType 多是 'rename' 或 'change',filename 是觸發事件的文件的名稱。
在大多數平臺,當目錄中一個文件出現或消失時,就會觸發 'rename' 事件。
fs.createReadStream(path[, options])
fs.createWriteStream(path[, options])
const fs = require('fs'); const ws = fs.createWriteStream('./demo.txt'); const tid = setInterval(() => { const num = parseInt(Math.random()*10); if (num < 8) { ws.write(num + ''); } else { clearInterval(tid); ws.end() } },200) ws.on('finish', () => { console.log('done'); })
fs 解決回調地獄問題
const fs = require('fs'); const promisify = require('util').promisify; const read = promisify(fs.readFile); // read('./promisify.js').then(data => { // console.log(data.toString()); // }).catch(ex => { // console.log(ex) // }) async function test() { try { const content = await read('./promisify.js'); console.log(content.toString()); } catch (ex) { console.log(ex); } } test();
path.normalize()
path.normalize() 方法會規範化給定的 path,並解析 '..' 和 '.' 片斷。
當發現多個連續的路徑分隔符時(如 POSIX 上的 / 與 Windows 上的 或 /),它們會被單個的路徑分隔符(POSIX 上是 /,Windows 上是 )替換。 末尾的多個分隔符會被保留。
若是 path 是一個長度爲零的字符串,則返回 '.',表示當前工做目錄。
例如,在 POSIX 上:
path.normalize('/foo/bar//baz/asdf/quux/..'); // 返回: '/foo/bar/baz/asdf'
在 Windows 上:
path.normalize('C:\\temp\\\\foo\\bar\\..\\'); // 返回: 'C:\\temp\\foo\\'
path.join([...paths])
path.join() 方法使用平臺特定的分隔符把所有給定的 path 片斷鏈接到一塊兒,並規範化生成的路徑。
長度爲零的 path 片斷會被忽略。 若是鏈接後的路徑字符串是一個長度爲零的字符串,則返回 '.',表示當前工做目錄。
若是任一路徑片斷不是一個字符串,則拋出 TypeError
例子:
path.join('/foo', 'bar', 'baz/asdf', 'quux', '..'); // 返回: '/foo/bar/baz/asdf' path.join('foo', {}, 'bar'); // 拋出 'TypeError: Path must be a string. Received {}'
path.resolve([...paths])
path.resolve() 方法會把一個路徑或路徑片斷的序列解析爲一個絕對路徑。
給定的路徑的序列是從右往左被處理的,後面每一個 path 被依次解析,直到構造完成一個絕對路徑。 例如,給定的路徑片斷的序列爲:/foo、/bar、baz,則調用 path.resolve('/foo', '/bar', 'baz') 會返回 /bar/baz
若是沒有傳入 path 片斷,則 path.resolve() 會返回當前工做目錄的絕對路徑
若是任何參數不是一個字符串,則拋出 TypeError
例子:
path.resolve('/foo/bar', './baz'); // 返回: '/foo/bar/baz' path.resolve('/foo/bar', '/tmp/file/'); // 返回: '/tmp/file' path.resolve('wwwroot', 'static_files/png/', '../gif/image.gif'); // 若是當前工做目錄爲 /home/myself/node, // 則返回 '/home/myself/node/wwwroot/static_files/gif/image.gif'
path.basename(path[, ext])
path <string>
ext <string> 可選的文件擴展名
path.basename() 方法返回一個 path 的最後一部分,相似於 Unix 中的 basename 命令
例子:
path.basename('/foo/bar/baz/asdf/quux.html'); // 返回: 'quux.html' path.basename('/foo/bar/baz/asdf/quux.html', '.html'); // 返回: 'quux'
path.extname(path)
path.extname() 方法返回 path 的擴展名,即從 path 的最後一部分中的最後一個 .(句號)字符到字符串結束。 若是 path 的最後一部分沒有 . 或 path 的文件名(見 path.basename())的第一個字符是 .,則返回一個空字符串。
若是 path 不是一個字符串,則拋出 TypeError
例子:
path.extname('index.html'); // 返回: '.html' path.extname('index.coffee.md'); // 返回: '.md' path.extname('index.'); // 返回: '.' path.extname('index'); // 返回: '' path.extname('.index'); // 返回: ''
path.dirname(path)
path.dirname() 方法返回一個 path 的目錄名,相似於 Unix 中的 dirname 命令
例子:
path.dirname('/foo/bar/baz/asdf/quux'); // 返回: '/foo/bar/baz/asdf'
path.parse(path)
path.parse() 方法返回一個對象,對象的屬性表示 path 的元素
返回的對象有如下屬性:
dir <string>
root <string>
base <string>
name <string>
ext <string>
例如,在 POSIX 上:
path.parse('/home/user/dir/file.txt'); // 返回: // { root: '/', // dir: '/home/user/dir', // base: 'file.txt', // ext: '.txt', // name: 'file' }
在 Windows 上:
path.parse('C:\\path\\dir\\file.txt'); // 返回: // { root: 'C:\\', // dir: 'C:\\path\\dir', // base: 'file.txt', // ext: '.txt', // name: 'file' }
path.format(pathObject)
pathObject <Object>
dir <string>
root <string>
base <string>
name <string>
ext <string>
path.format() 方法會從一個對象返回一個路徑字符串。 與 path.parse() 相反。
當 pathObject 提供的屬性有組合時,有些屬性的優先級比其餘的高:
若是提供了 pathObject.dir,則 pathObject.root 會被忽略
若是提供了 pathObject.base 存在,則 pathObject.ext 和 pathObject.name 會被忽略
例如,在 POSIX 上:
// 若是提供了 `dir`、`root` 和 `base`,則返回 `${dir}${path.sep}${base}`。 // `root` 會被忽略。 path.format({ root: '/ignored', dir: '/home/user/dir', base: 'file.txt' }); // 返回: '/home/user/dir/file.txt' // 若是沒有指定 `dir`,則 `root` 會被使用。 // 若是隻提供了 `root` 或 `dir` 等於 `root`,則平臺的分隔符不會被包含。 // `ext` 會被忽略。 path.format({ root: '/', base: 'file.txt', ext: 'ignored' }); // 返回: '/file.txt' // 若是沒有指定 `base`,則 `name` + `ext` 會被使用。 path.format({ root: '/', name: 'file', ext: '.txt' }); // 返回: '/file.txt'
在 Windows 上:
path.format({ dir: 'C:\\path\\dir', base: 'file.txt' }); // 返回: 'C:\\path\\dir\\file.txt'
path.sep
提供了平臺特定的路徑片斷分隔符:
Windows 上是 \
POSIX 上是 /
例如,在 POSIX 上:
'foo/bar/baz'.split(path.sep); // 返回: ['foo', 'bar', 'baz']
在 Windows 上:
'foo\\bar\\baz'.split(path.sep); // 返回: ['foo', 'bar', 'baz']
path.delimiter
提供平臺特定的路徑分隔符:
Windows 上是 ;
POSIX 上是 :
例如,在 POSIX 上:
console.log(process.env.PATH); // 輸出: '/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin' process.env.PATH.split(path.delimiter); // 返回: ['/usr/bin', '/bin', '/usr/sbin', '/sbin', '/usr/local/bin']
在 Windows 上:
console.log(process.env.PATH); // 輸出: 'C:\Windows\system32;C:\Windows;C:\Program Files\node\' process.env.PATH.split(path.delimiter); // 返回: ['C:\\Windows\\system32', 'C:\\Windows', 'C:\\Program Files\\node\\']
path.win32
path.win32 屬性提供了 path 方法針對 Windows 的實現
path.posix
path.posix 屬性提供了 path 方法針對 POSIX 的實現
__dirname
、__filename
老是返回文件的絕對路徑
process.cwd()
老是返回執行node命令所在文件夾
./
:在require方法中老是相對於當前文件所在文件夾
在其餘地方和process.cwd()同樣,相對於node啓動文件夾
在 ECMAScript 2015 引入 TypedArray 以前,JavaScript 語言沒有讀取或操做二進制數據流的機制。 Buffer 類被引入做爲 Node.js API 的一部分,使其能夠在 TCP 流或文件系統操做等場景中處理二進制數據流。
TypedArray 現已被添加進 ES6 中,Buffer 類以一種更優化、更適合 Node.js 用例的方式實現了 Uint8Array API。
Buffer 類的實例相似於整數數組,但 Buffer 的大小是固定的、且在 V8 堆外分配物理內存。 Buffer 的大小在被建立時肯定,且沒法調整。
Buffer 類在 Node.js 中是一個全局變量,所以無需使用 require('buffer').Buffer。
Buffer.alloc(size[, fill[, encoding]])
size <integer> 新建的 Buffer 指望的長度
fill <string> | <Buffer> | <integer> 用來預填充新建的 Buffer 的值。 默認: 0
encoding <string> 若是 fill 是字符串,則該值是它的字符編碼。 默認: 'utf8'
分配一個大小爲 size 字節的新建的 Buffer 。 若是 fill 爲 undefined ,則該 Buffer 會用 0 填充。
例子:
const buf = Buffer.alloc(5); // 輸出: <Buffer 00 00 00 00 00> console.log(buf);
若是同時指定了 fill 和 encoding ,則會調用 buf.fill(fill, encoding) 初始化分配的 Buffer 。
const buf = Buffer.alloc(11, 'aGVsbG8gd29ybGQ=', 'base64'); // 輸出: <Buffer 68 65 6c 6c 6f 20 77 6f 72 6c 64> console.log(buf);
調用 Buffer.alloc() 會明顯地比另外一個方法 Buffer.allocUnsafe() 慢,可是能確保新建的 Buffer 實例的內容不會包含敏感數據。
Buffer.allocUnsafe(size)
分配一個大小爲 size 字節的新建的 Buffer 。 若是 size 大於 buffer.constants.MAX_LENGTH 或小於 0,則拋出 [RangeError] 錯誤。 若是 size 爲 0,則建立一個長度爲 0 的 Buffer。
以這種方式建立的 Buffer 實例的底層內存是未初始化的。 新建立的 Buffer 的內容是未知的,且可能包含敏感數據。 可使用 buf.fill(0) 初始化 Buffer 實例爲0。
const buf = Buffer.allocUnsafe(10); // 輸出: (內容可能不一樣): <Buffer a0 8b 28 3f 01 00 00 00 50 32> console.log(buf); buf.fill(0); // 輸出: <Buffer 00 00 00 00 00 00 00 00 00 00> console.log(buf);
Buffer.byteLength(string[, encoding])
返回一個字符串的實際字節長度。 這與 String.prototype.length 不一樣,由於那返回字符串的字符數
Buffer.isBuffer(obj)
若是 obj 是一個 Buffer 則返回 true ,不然返回 false。
Buffer.concat(list[, totalLength])
list <Array> 要合併的 Buffer 或 Uint8Array 實例的數組
totalLength <integer> 合併時 list 中 Buffer 實例的總長度
返回一個合併了 list 中全部 Buffer 實例的新建的 Buffer 。
若是 list 中沒有元素、或 totalLength 爲 0 ,則返回一個新建的長度爲 0 的 Buffer 。
const buf1 = Buffer.alloc(10); const buf2 = Buffer.alloc(14); const buf3 = Buffer.alloc(18); const totalLength = buf1.length + buf2.length + buf3.length; // 輸出: 42 console.log(totalLength); const bufA = Buffer.concat([buf1, buf2, buf3], totalLength); // 輸出: <Buffer 00 00 00 00 ...> console.log(bufA); // 輸出: 42 console.log(bufA.length);
buf.length
返回 buf 在字節數上分配的內存量。
const buf = Buffer.alloc(1234); // 輸出: 1234 console.log(buf.length);
buf.toString([encoding[, start[, end]]])
encoding <string> 解碼使用的字符編碼。默認: 'utf8'
start <integer> 開始解碼的字節偏移量。默認: 0
end <integer> 結束解碼的字節偏移量(不包含)。 默認: buf.length
根據 encoding 指定的字符編碼解碼 buf 成一個字符串。 start 和 end 可傳入用於只解碼 buf 的一部分。
const buf1 = Buffer.allocUnsafe(26); for (let i = 0; i < 26; i++) { // 97 是 'a' 的十進制 ASCII 值 buf1[i] = i + 97; } // 輸出: abcdefghijklmnopqrstuvwxyz console.log(buf1.toString('ascii')); // 輸出: abcde console.log(buf1.toString('ascii', 0, 5));
buf.fill(value[, offset[, end]][, encoding])
value <string> | <Buffer> | <integer> 用來填充 buf 的值。
offset <integer> 開始填充 buf 前要跳過的字節數。默認: 0。
end <integer> 結束填充 buf 的位置(不包含)。默認: buf.length。
encoding <string> 若是 value 是一個字符串,則這是它的字符編碼。默認: 'utf8'。
buf.equals(otherBuffer)
若是 buf 與 otherBuffer 具備徹底相同的字節,則返回 true,不然返回 false。
const buf1 = Buffer.from('ABC'); const buf2 = Buffer.from('414243', 'hex'); const buf3 = Buffer.from('ABCD'); // 輸出: true console.log(buf1.equals(buf2)); // 輸出: false console.log(buf1.equals(buf3));
buf.indexOf(value[, byteOffset][, encoding])
buf 中 value 首次出現的索引,若是 buf 沒包含 value 則返回 -1
value <string> | <Buffer> | <Uint8Array> | <integer> 要搜索的值
byteOffset <integer> buf 中開始搜索的位置。默認: 0
encoding <string> 若是 value 是一個字符串,則這是它的字符編碼。 默認: 'utf8'
const buf = Buffer.from('this is a buffer'); // 輸出: 0 console.log(buf.indexOf('this')); // 輸出: 2 console.log(buf.indexOf('is')); // 輸出: 8 console.log(buf.indexOf(Buffer.from('a buffer'))); // 輸出: 8 // (97 是 'a' 的十進制 ASCII 值) console.log(buf.indexOf(97)); // 輸出: -1 console.log(buf.indexOf(Buffer.from('a buffer example')));
buf.copy(target[, targetStart[, sourceStart[, sourceEnd]]])
target <Buffer> | <Uint8Array> 要拷貝進的 Buffer 或 Uint8Array。
targetStart <integer> target 中開始拷貝進的偏移量。 默認: 0
sourceStart <integer> buf 中開始拷貝的偏移量。 默認: 0
sourceEnd <integer> buf 中結束拷貝的偏移量(不包含)。 默認: buf.length
拷貝 buf 的一個區域的數據到 target 的一個區域,即使 target 的內存區域與 buf 的重疊。
buf 解決中文字符串亂碼問題
const StringDecoder = require('string_decoder').StringDecoder; const decoder = new StringDecoder('utf8'); const buf = Buffer.from('中文字符串!'); //for (let i = 0; i < buf.length; i+= 5) { // const b = Buffer.allocUnsafe(5); // buf.copy(b,0,i); // console.log(b.toString()); //} for (let i = 0; i < buf.length; i+= 5) { const b = Buffer.allocUnsafe(5); buf.copy(b,0,i); console.log(decoder.write(b)); }
process 對象是一個全局變量,它提供當前 Node.js 進程的有關信息,以及控制當前 Node.js 進程。 由於是全局變量,因此無需使用 require()。
process.stdin
process.stdin 屬性返回鏈接到 stdin (fd 0)的流。 它是一個net.Socket(它是一個Duplex流),除非 fd 0指向一個文件,在這種狀況下它是一個Readable流。process.stdout
process.stdout 屬性返回鏈接到 stdout (fd 1)的流。 它是一個net.Socket (它是一個Duplex流), 除非 fd 1 指向一個文件,在這種狀況下它是一個[可寫][]流。
例1: 將輸入流數據輸出到輸出流,即輸出到終端。
process.stdin.pipe(process.stdout);
● HTTP是無狀態協議。簡單地說,當你瀏覽了一個頁面,而後轉到同一個網站的另外一個頁面,服務器沒法認識到,這是同一個瀏覽器在訪問同一個網站。每一次的訪問,都是沒有任何關係的。
那麼世界就亂套了,好比我上一次訪問,登錄了,下一次訪問,又讓我登錄,不存在登錄這事兒了。
● Cookie是一個簡單到爆的想法:當訪問一個頁面的時候,服務器在下行HTTP報文中,命令瀏覽器存儲一個字符串;瀏覽器再訪問同一個域的時候,將把這個字符串攜帶到上行HTTP請求中。
● 第一次訪問一個服務器,不可能攜帶cookie。 必須是服務器獲得此次請求,在下行響應報頭中,攜帶cookie信息,此後每一次瀏覽器往這個服務器發出的請求,都會攜帶這個cookie。
特色
● cookie是不加密的,用戶能夠自由看到;
● 用戶能夠刪除cookie,或者禁用它
● cookie能夠被篡改
● cookie能夠用於攻擊
● cookie存儲量很小。將來實際上要被localStorage替代,可是後者IE9兼容。
express中的cookie,你確定能想到。 res負責設置cookie, req負責識別cookie。
cookie實例
var express = require('express'); var cookieParser = require('cookie-parser'); var app = express(); //使用cookie必需要使用cookie-parser中間件 app.use(cookieParser()); app.get("/",function(req,res){ res.send("猜你喜歡" + req.cookies.mudidi); }); //查詢一個地方的攻略,URL語法: http://127.0.0.1/gonglue?mididi=北京 //此時北京就能記錄在cookie中 app.get("/gonglue",function(req,res){ //獲得get請求,用戶查詢的目的地 var mudidi = req.query.mudidi; //記錄用戶喜愛 //先讀取用戶的喜愛,而後把新的數據push進入數組,而後設置新的cookie var mudidiarry = req.cookies.mudidi || []; mudidiarry.push(mudidi); //maxAge在Express中以毫秒爲單位 res.cookie("mudidi",mudidiarry,{maxAge: 900000, httpOnly: true}); res.send(mudidi + "旅遊攻略"); }); app.listen(3000);
session依賴cookie,當一個瀏覽器禁用cookie的時候,登錄效果消失; 或者用戶清除了cookie,登錄也消失。
session比cookie不同在哪裏呢? session下發的是亂碼,而且服務器本身緩存一些東西,下次瀏覽器的請求帶着亂碼上來,此時與緩存進行比較,看看是誰。
因此,一個亂碼,能夠對應無限大的數據。
任何語言中,session的使用,是「機理透明」的。他是幫你設置cookie的,可是足夠方便,讓你感受不到這事兒和cookie有關。session實例
var express = require("express"); var app = express(); var session = require("express-session"); app.use(session({ secret: 'keyboard cat', resave: false, saveUninitialized: true })); app.get("/",function(req,res){ if(req.session.login == "1"){ res.send("歡迎" + req.session.username); }else{ res.send("沒有成功登錄"); } }); app.get("/login",function(req,res){ req.session.login = "1"; //設置這個session req.session.username = "考拉"; res.send("你已經成功登錄"); }); app.listen(3000);
MD5加密是函數型加密。就是每次加密的結果必定相同,沒有隨機位。
特色:
● 無論加密的文字,多長多短,永遠都是32位英語字母、數字混合。
● 哪怕只改一個字,密文都會大變。
● MD5沒有反函數破解的可能,網上的破解工具,都是經過字典的模式,經過大量列出明-密對應的字典,找到明碼。兩次加密網上也有對應的字典。因此咱們不要直接用一層md5,這樣對黑客來講和明碼是同樣。
MD5經常使用於做爲版本校驗。能夠比對兩個軟件、文件是否徹底一致。
node中自帶了一個模塊,叫作crypto
模塊,負責加密。
首先建立hash,而後update和digest:
var crypto = require("crypto"); module.exports = function(mingma){ var md5 = crypto.createHash('md5'); var password = md5.update(mingma).digest('base64'); return password; }
一個基於node的開發框架
express,不會在node上進行2次抽象,而是在node自己上提供擴展
徹底由路由和中間件組成,從本質上來講express就是根據路由對先後端進行橋接
中間件(middleware)指的就是一個函數,能夠訪問請求對象,也能夠訪問響應對象,能夠訪問請求和響應循環中的下一個中間件
npm init npm i express -g npm i express-generator -g //專門供windows使用 切換到指定項目目錄 npm i express --save-dev npm i express-generator --save-dev
var express = require("express"); var app = express(); app.get("/",(req,res) => { res.write("this is homePage") }) app.get("/login",(req,res) => { res.send("this is loginPage") }) var server = app.listen(3000,"127.0.0.1",() => { console.log("express hello_world") })
路由響應方法
方法 | 描述 |
---|---|
res.download() | 提示下載文件 |
res.end() | 終結響應處理流程 |
res.json() | 發送JSON響應 |
res.jsonp() | 發送一個支持JSONP的JSON格式的響應 |
res.redirect() | 重定向請求 |
res.send() | 發送各類類型的響應 |
res.sendFile() | 以八位字節流的形式發送文件 |
res.sendStatus() | 設置響應狀態代碼並將其以字符串形式做爲響應體的一部分發送。 |
利用express中內置的腳手架構建項目
在指定目錄下express -e project_name
cd project_name
npm install
npm install
body-parser 幫助對請求體進行解析 cookie-parser 給cookie提供解析 debug 幫助在控制檯上輸出debug信息 ejs javascript 一個模板引擎 morgan 幫助在控制檯上反饋request的信息 serve-favicon 主要是爲了解決初始化請求favicon圖標問題
app.set(event, str) 設定一些參數 __dirname 絕對路徑 app.use(path,callback) 接受中間件並執行 res.sendFile(absolutePath--絕對路徑)
<%= %> 輸出內容標籤 <%- %> 輸出html內容標籤 <% %> 流程標籤 能夠執行js代碼 <%# %> 註釋標籤 <%- include(path) %> 引入標籤
利用express+mongodb實現一個從登陸、註冊、註銷到評論頁、詳情頁的微型先後端電商平臺,具體代碼見github:
https://github.com/Jack-cool/expressPro
app.js
var createError = require('http-errors'); var express = require('express'); var path = require('path'); var cookieParser = require('cookie-parser'); var logger = require('morgan'); var session = require('express-session'); var indexRouter = require('./routes/index'); var usersRouter = require('./routes/users'); var commentRouter = require('./routes/comment'); // var async = require('async'); var app = express(); // view engine setup app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'ejs'); app.use(logger('dev')); app.use(express.json()); app.use(express.urlencoded({ extended: false })); app.use(cookieParser()); app.use(express.static(path.join(__dirname, 'public'))); app.use(session({ secret: 'recommend 128 bytes random string', // 對session id 相關的cookie 進行簽名 cookie: { maxAge: 20*60*1000 }, // // 設置 session 的有效時間,單位毫秒 resave: true, saveUninitialized: true // 是否保存未初始化的會話 })) app.use('/', indexRouter); app.use('/users', usersRouter); app.use('/comment', commentRouter); // catch 404 and forward to error handler app.use(function(req, res, next) { next(createError(404)); }); // error handler app.use(function(err, req, res, next) { // set locals, only providing error in development res.locals.message = err.message; res.locals.error = req.app.get('env') === 'development' ? err : {}; // render the error page res.status(err.status || 500); res.render('error'); }); module.exports = app;
routes/index.js
var express = require('express'); var router = express.Router(); /* GET home page. */ router.get('/', function(req, res, next) { res.render('index', { title: 'Home', username: req.session.username }); }); router.get('/register', function(req, res, next) { res.render('register', { title: '註冊頁' }); }); router.get('/login', function(req, res, next) { res.render('login', { title: '登陸頁'}) }); router.get('/logout', function(req,res,next) { // req.session.username = undefined; // res.redirect('/'); req.session.destroy(function(err) { if (err) { console.log(err); } else { res.redirect("/"); } }) }); router.get('/comment', function(req,res,next) { res.render('comment', { title: '評論頁' }) }) module.exports = router;
routes/users.js
var express = require('express'); var MongoClient = require('mongodb').MongoClient; var DB_CONNECT_STR = "mongodb://localhost:27017/users" var router = express.Router(); /* GET users listing. */ router.get('/', function(req, res, next) { res.send('respond with a resource'); }); router.post('/register',function(req,res){ // res.send('註冊成功'); console.log('註冊信息',req.body); var username = req.body.reg_name; var nickname = req.body.reg_nickname; var pwd = req.body.reg_pwd; var insertData = function(db,callback) { // 關聯集合 var data = [{ username:username,nickname:nickname,pwd:pwd }] var conn = db.collection('front'); conn.insert(data,function(err,result) { if (err) { console.log(err) } else { callback(result); } }) } // 鏈接數據庫 MongoClient.connect(DB_CONNECT_STR,function(err,db) { if (err) { console.log('鏈接數據庫失敗'); } else { console.log('鏈接數據庫成功'); insertData(db,function(result) { res.send('哈哈,你已經註冊成功了呦~~~') db.close(); }) } }) }) router.post('/login', function(req,res,next) { var username = req.body.log_name; var nickname = req.body.log_nickname; var pwd = req.body.log_pwd; var findData = function(db,callback) { // 查詢條件 var data = { username:username,nickname:nickname,pwd:pwd } // 關聯集合 var conn = db.collection('front'); conn.find(data).toArray(function(err,result) { if (err) { console.log(err); } else { callback(result); } }) } // 鏈接數據庫 MongoClient.connect(DB_CONNECT_STR,function(err,db) { if (err) { console.log('鏈接數據庫失敗'); } else { findData(db,function(result) { console.log('登錄數據~~',result); if (result.length > 0) { req.session.username = result[0].username; res.redirect('/'); } else { res.send('登錄失敗'); } db.close(); }) } }) }) module.exports = router;
routes/comment.js
var express = require('express'); var async = require('async'); var MongoClient = require('mongodb').MongoClient; var DB_CONNECT_STR = "mongodb://localhost:27017/users"; var router = express.Router(); /* GET home page. */ router.post('/save', function(req, res, next) { // res.send('發佈成功'); console.log('評論信息',req.body); var title = req.body.comment_title; var content = req.body.comment_content; // var insertData = function(db,callback) { // // 關聯集合 // var data = [{ title:title,content:content }]; // var conn = db.collection('comments'); // conn.insert(data,function(err,result) { // if (err) { // console.log(err); // } else { // callback(result); // } // }) // } var updateData = function(db,callback) { var conn = db.collection('comments'); var ids = db.collection('ids'); async.waterfall([function(callback){ ids.findAndModify({name:'comments'},[["_id","desc"]],{$inc:{id:1}},function(err,result){ callback(null,result.value.id) }) },function(id,callback){ var data = [{uid:id,title:title,content:content,username:req.session.username}]; conn.insert(data,function(result){ callback(result) }) }],function(err,result){ if (err) { console.log(err); } else { callback(result); } }) } MongoClient.connect(DB_CONNECT_STR,function(err,db) { if (err) { console.log('鏈接數據庫失敗'); } else { console.log('鏈接數據庫成功'); // insertData(db,function(result) { // res.send('嘻嘻嘻,你發佈成功了呦~~~'); // db.close(); // }) updateData(db,function(result) { // res.send('嘻嘻嘻,你發佈成功了呦~~~'); res.redirect('/comment/list'); db.close(); }) } }) }); router.get('/list',function(req,res) { var findData = function(db,callback) { var conn = db.collection('comments'); conn.find({}).toArray(function(err,result) { if (err) { console.log(err); } else { callback(result); } }) } MongoClient.connect(DB_CONNECT_STR,function(err,db){ if (err) { console.log(err); } else { findData(db,function(result) { if (result.length > 0) { console.log('評論列表頁信息',result); res.render('list',{ title:'列表頁',list:result }); } else { res.send('親,沒有評論信息~~'); } }) } }) }) router.get('/detail',function(req,res) { // res.send('列表頁'); var uid = parseInt(req.query.uid); MongoClient.connect(DB_CONNECT_STR,function(err,db) { var conn = db.collection('comments'); conn.find({uid:uid}).toArray(function(err,result) { if (err) { console.log(err); } else { console.log('詳情頁信息',result); res.render('detail',{ title:'詳情頁',mes:result }); } }) }) }) module.exports = router;
文檔持續更新中~~~