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;
文档持续更新中~~~