node.js
1 2 3 4 5 6 7
|
1. 基于 [Express 框架](http: 2. 基于 [Electron 框架](https: 3. 基于 [restify 框架](http: 4. 读写和操作数据库、创建实用的命令行工具辅助前端开发、etc…
|
终端命令
1 2 3 4 5 6 7 8 9 10 11 12 13
| esc cls tab dir cd.>文件 md
在文件地址栏直接cmd可以打开当前目录路径的cmd终端窗口
shift+右键 打开powershell终端 New-Item 文件
|
文件读写模块(fs)
1 2 3 4 5 6 7
| File system
var fs = require('fs') readFile writeFile mkdir readdirSync
|
文件写入
1 2 3 4 5 6 7 8 9 10 11 12 13
| fs.writeFile(file, data[, options], callback)
fs.writeFile('./hello.txt',msg,'utf8',function(err){ if(err){ console.log('写文件出错了! 具体错误:' + err); }else{ console.log('ok'); } });
|
文件读取
1 2 3 4 5 6 7 8 9 10 11
| fs.readFile(path[, options], callback)
fs.readFile('./hello.txt','utf8',function(err,data){ if(err){ throw err; } console.log(data.toString('utf8')); })
|
创建文件夹
1
| fs.mkdir(path[, mode], callback)
|
获取文件名字
1
| fs.readdirSync(path[, options])
|
解决在文件读取中 ./ 相对路径的问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
fs.readFile('./hello.txt','utf8',function(err,data){ if(err){ throw err; } console.log(data) })
var fs = require('fs'); var filename = __dirname + '\\' + 'hello.txt';
|
Path模块
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| const path = require('path'); var filename = path.join(__dirname,'hello.txt');
fs.readFile(filename,'utf8',function(err,data){ if(err){ throw err; } console.log(data) })
path.basename(路径) path.extname(路径)
|
创建目录
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| var fs = require('fs');
fs.mkdir('test-mkdir',function(err){ if(err){ console.log('创建目录出错了,详细信息如下:'); console.log(err); }else{ console.log('目录创建成功!'); } })
fs.mkdir('根目录',function(err){ if(err){ throw err; } fs.mkdir('./根目录/子目录1'); fs.mkdir('./根目录/子目录2'); fs.mkdir('./根目录/子目录3'); fs.mkdir('./根目录/子目录4'); })
|
错误优先
HTTP模块
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
|
var http = require('http');
var server = http.createServer();
server.on('request',function(req,res){ res.write('Hello World!!!'); res.end(); });
server.listen(8080,function(){ console.log('服务器启动了,请访问:http://localhost:8080'); });
var http = require('http'); http.createServer(function(req,res){ res.end(); }).listen(8080,function(){ console.log('http://localhost:8080'); });
|
解决中文乱码
1 2
| res.setHeader('Content-Type','text/plain;charset=utf-8');
|
根据用户不同请求,做出不同响应(响应现有的 HTML 文件)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
|
var http = require('http');
var fs = require('fs');
var path = require('path');
http.createServer(function(req,res){ if(req.url === '/' || req.url === '/index'){ fs.readFile(path.join(__dirname,'htmls','index.html'),function(err,data){ if(err){ throw err; } res.end(data); }) }else if(req.url === '/login'){ fs.readFile(path.join(__dirname,'htmls','login.html'),function(err,data){ if(err){ throw err; } res.end(data); }) }else{ fs.readFile(path.join(__dirname,'htmls','404.html'),function(err,data){ if(err){ throw err; } res.end(data); }) } }).listen(9090,function(){ console.log('http://localhost:9090'); });
|
响应图片
1 2 3 4 5 6 7 8 9 10
| else if(req.url === '/images/index.jpg'){ fs.readFile(path.join(__dirname,'images','index.jpg'),function(err,data){ if(err){ throw err; } res.setHeader('Content-Type','image/jpeg'); res.end(data); }) }
|
响应css
1 2 3 4 5 6 7 8 9 10
| else if(req.url === '/css/index.css'){ fs.readFile(path.join(__dirname,'css','index.css'),function(err,data){ if(err){ throw err; } res.setHeader('Content-Type','text/css'); res.end(data); }) }
|
自定义模块
1 2
| const m1 = require('./mi.js');
|
向外共享
moment模块
package.json和package-lock.json
mime模块
1 2 3 4
| npm install mime const mime = require('mime'); mime.getType('txt'); mime.getExtension('text/plain');
|
获取一个目录下的所有静态资源
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
|
var http = require('http'); var path = require('path'); var fs = require('fs'); var mime = require('mime');
http.createServer(function(req,res){ var publicDir = path.join(__dirname,'public');
var filename = path.join(publicDir,req.url);
fs.readFile(filename,function(err,data){ if(err){ res.end('文件不存在 404'); }else{
res.setHeader('Content-Type',mime.getType(filename)); res.end(data); } })
}).listen(9090,function(){ console.log('http://localhost:9090'); })
|
对于服务器来说URL请求就是一个标识符
1 2 3 4 5 6 7 8 9
| else if(req.url === '/haha.xxx'){ fs.readFile(path.join(__dirname,'index.jpg'),function(err,data){ if(err){ throw err; } res.setHeader('Content-Type','image/jpeg') res.end(data); }); }
|
request 和 response 对象介绍
request 对象
1 2 3 4 5 6 7
| request 对象类型 <http.IncomingMessage>,继承自stream.Readable request 对象常用成员 request.headers request.rawHeader request.httpVersion request.method request.url
|
response对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| 1. res.write() 2. 每个请求都必须要调用的一个方法 res.end(); 结束响应(请求) 告诉服务器该响应的报文头,报文体等等全部已经响应完毕,可以考虑本次响应结束。 res.end() 要响应数据的话,数据必须是String类型或者是Buffer类型 4. 通过 res.setHeader() 来设置响应报文头 5. 设置http响应状态码 6. res.writeHead() res.writeHead(404,'Not Found',{ 'Content-Type':'text/html;charset=utf-8' });
|
NPM全局安装
1 2 3 4 5
| npm install 包名 -g
npm install mime -g
mime a.txt
|
NPM常用命令
1 2 3 4 5 6 7 8
| 1. install,安装包。npm install 包名
2. uninstall,卸载包。npm uninstall 包名 3. version,查看当前npm版本。npm version 或 npm -v 4. init,创建一个package.json文件(包描述文件,元数据,有这个文件才是包)。npm init 5. 注意:当使用 npm init -y 的时候,如果当前文件夹(目录)的名字比较怪(有大写,有中文等等)就会影响 npm init -y 的一步生成操作,此时需要 npm init 根据向导来生成
npm uninstall 具体包名
|
npm安装版本号
1 2 3
| 第一位数字 大版本 第二位数字 功能版本 第三位数字 bug修复版本
|
包的分类
1 2 3 4 5 6 7 8 9
| npm i 包名 -D npm i --save-dev
npm install 包名 npm i 包名 npm i --save 包名 npm i -S 包名
|
解决npm下包速度慢的问题
nrm
1 2 3 4 5
|
npm i nrm -g nrm ls nrm use taobao
|
i5ting_toc
1 2 3 4
|
npm install -g i5ting_toc i5ting_toc -f 要转换的md文件路径 -o
|
包的结构
1 2 3 4
| 一个规范的包,它的组成结构,必须符合以下 3 点要求: 1. 包必须以单独的目录而存在 2. 包的顶级目录下要必须包含 package.json 这个包管理配置文件 3. package.json 中必须包含 name,version,main 这三个属性,分别代表包的名字、版本号、包的入口。
|
发包相关命令
1 2 3 4 5 6
| npm login npm whoami
npm publish npm unpublish npm unpublish 包名 --force
|
Express
创建基本web服务器
1 2 3 4 5 6 7 8 9
| const express = require('express')
const app = express()
app.listen(3000, () => { console.log('running……') })
|
监听 GET 和 POST 请求,并响应客户端
1 2 3
| app.get('/', (req, res) => res.send('Hello World!')) app.post('/', (req, res) => res.send('Hello World!'))
|
获取 URL 中携带的查询参数
1 2 3 4 5 6
| app.get('/', (req, res) => { console.log(req.query) res.send(req.query) })
|
获取URL的的动态参数
/:id
– id 值不是固定的,可以自己定义,例如: /:ids
- 展示到页面中的
id
键,是自定义的变量值
- 参数可以有多个,例如:
/:ids/:name
1 2 3 4 5
| app.get('/user/:id', (req, res) => { console.log(req.params) res.send(req.params) })
|
托管静态资源目录
1 2 3 4 5 6 7
| app.use(express.static('public'))
app.use(express.static('public'),express.static('public'))
app.use('public',express.static('public'))
|
路由
路由模块化
- 创建路由模块对应的 .js 文件
- 调用 express.Router() 函数创建路由对象
- 向路由对象上挂载具体的路由
- 使用 module.exports 向外共享路由对象
- 使用 app.use() 函数注册路由模块
express.Router()
app.use()
1 2 3 4 5
| app.use((req,res,next)=>{ console.log('全局中间件函数被触发了') next() })
|
express中间件
所谓的中间件(Middleware
),特指业务流程的中间处理环节
局部生效的中间件
1 2 3 4 5 6
| const fn = function(req,res,next){ console.log('局部中间件函数被触发了'); next(); }
app.post('/',fn,function(req,res){});
|
中间件可以调用多个
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| const mv1 = (req, res, next) => { console.log('这是第一个中间件函数') next() }
const mv2 = (req, res, next) => { console.log('这是第二个中间件函数') next() } app.get('/', mv1, mv2, (req, res) => { res.send('Home Page') }) app.get('/user', [mv1, mv2], (req, res) => { res.send('Home Page') })
|
中间件的注意事项
1 2 3 4 5
| 1. 一定要在路由之前注册中间件 (看自己需求) 2. 客户端发送过来的请求,可以连续调用多个中间件进行处理 3. 执行完中间件的业务代码之后,不要忘记调用 `next()` 函数 (看自己需求) 4. 为了防止代码逻辑混乱,调用 `next()` 函数后不要再写额外的代码 (看自己需求) 5. 连续调用多个中间件时,多个中间件之间,共享 `req` 和 `res` 对象
|
中间件的分类
1. 应用级别的中间件
通过 app.use() 或 app.METHOD() 函数,绑定到 app 实例上的中间件,叫做应用级别的中间件
2. 路由级别的中间件
- 绑定到 express.Router() 实例上的中间件,叫做路由级别的中间件
- 用法上和应用级别中间件没有任何区别,只不过,应用级别中间件是绑定到 app 实例上,路由级别中间件绑定到 router 实例上
1 2 3 4 5 6 7 8 9 10 11
| var app = express() var router = express.Router()
router.use(function(req,res,next){ console.log('Time:',Data.now()) next() })
app.use('/',router)
|
3. 错误级别中间件
- 错误级别中间件的作用: 专门用来捕获整个项目中发生的异常错误,从而防止项目异常崩溃的问题
- 格式:错误级别中间件的 function 处理函数中,必须是 4 个形参,形参顺序从前到后,分别是
(err, req, res, next)
- 注意: 错误级别的中间件,必须注册在所有路由之后(因为捕获不到之后出现的异常)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| app.get('/', (req, res) => { throw new Error('服务器内部发生了错误') res.send('Home Page.') }) app.use((err, req, res, next) => { console.log('发生了错误:' + err.message) res.send(err.message) })
|
异常的类别
- 编译异常(程序运行不了)
- 运行异常(程序能运行起来)
4.Express内置中间件
- express.static 快速托管静态资源的内置中间件,例如: HTML 文件、图片、CSS 样式等(无兼容性)
- express.json 解析 JSON 格式的请求体数据(有兼容性,仅在 4.16.0+ 版本中可用)
- express.urlencoded 解析 URL-encoded 格式的请求体数据(有兼容性,仅在 4.16.0+ 版本中可用)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| app.use(express.json())
app.use(express.urlencoded({extended:false}))
urlencoded 默认为 true true: 使用第三方包 qs 解析 请求体数据 false: 使用内置模块 querystring 解析 请求体数据 qs 比 querystring 复杂(更强大), 但是内置模块 querystring 已经足够使用了, 所以里面的参数可以省略不写 express.urlencoded()
|
5. 第三方的中间件
1 2
| npm i body-parser req.body
|
自定义中间件
data事件
如果数据量比较大,无法一次性发送完毕,则客户端会把数据切割后,分批发送到服务器。所以 data 事件可能会触发多次,每一次触发 data 事件时,获取到数据只是完整数据的一部分,需要手动对接收到的数据进行拼接。
1 2 3 4 5 6 7
| let str = '';
req.on('data',(chunk)=>{ str += chunk; })
|
end事件
1 2 3 4 5
| req.on('end',()=>{ console.log(str) })
|
querystring
1 2 3 4 5
| const qs = require('querystring');
const body = qs.parse(str)
|
cors跨域
1 2 3
| npm i cors const cors = require('cors'); app.use(cors())
|
try-catch与异步操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
var fs = require('fs'); try{ fs.writeFile('./xxx/abc.txt','大家早上好!','utf8',function(err){ console.log('ok'); }); }catch(e){ console.log('出错了!'+e) }
|
URL模块
1
| var url = require('url');
|
把用户提交的新闻数据保存到data.json文件中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
|
var list = []; list.push(urlObj.query);
fs.writeFile(path.join(__dirname,'data','data.json'),JSON.stringify(list),function(err){ if(err){ throw err; } console.log('OK'); res.statusCode = 302; res.statusMessage = 'Found'; res.setHeader('Location','/'); res.end(); )
|
querystring模块
1 2 3 4
| var querystring = require('querystring');
postBody = querystring.parse(postBody);
|
underscore.js
其他
1 2 3 4 5 6 7 8
| decodeURI(filename); modules.paths Buffer.from() Buffer.byteLength(str,'utf8');
--save 添加到依赖项 package.json文件中dependencies依赖列表中
|