Node.js
索引:
– fs文件处理模块
– path路径处理模块
– os 操作系统处理模块
– http服务构建模块
– 响应内容类型content-type
– 客户端渲染与服务端渲染
– 模板引擎art-template
– 模块作用域与访问
– require加载模块规则
– package.json与package-lock.json
– 重定向
– 获取表单提交信息
– Express json响应方法
– Promise
–中间件
最近一次更新:2020-08-16
- fs模块
(1)读取文件readFile
参数一:文件路径
不是相对于当前文件路径,而是相对于执行node命令所处的路径,有时为处理适配跨目录读取文件,可借助动态获取当前目录绝对路径的方式__dirname
参数二:回调函数(err data)
文件存储/返回的data默认是二进制数据,如果需要处理或操作(如模板引擎),需要通过toString()方法或设置utf8转换为字符串;
var fs=require('fs');
var path=require('path');
fs.readFile(path.join(__dirname,"./01-helloword.js"),function(error,data){
if(error){
console.log('执行失败');
}else{
console.log(data.toString();
}
})
OR
fs.readFile((path.join(__dirname,"./01-helloword.js"),'utf8',function(error,data){
if(error){
console.log('执行失败');
}else{
console.log(data);
}
})
(2)写入文件wirteFile
参数一:文件路径及文件名
参数二:要写入的内容
参数三:回调函数 (err)
var fs=require('fs');
var path=require('path');
fs.writeFile(path.join(__dirname,'./data.md'),'for testing only',function(err){
if(err){
console.log('Failed');
}else{
console.log('Success');
}
})
- path模块
//有以下方法可以调用/获取
resolve: [Function: resolve], -- 以程序为根目录,作为起点,根据参数解析出一个绝对路径;以应用程序为根目录;普通字符串代表子目录;/代表绝对路径根目录;如果遇到/会直接回到当前程序的根目录
normalize: [Function: normalize],
isAbsolute: [Function: isAbsolute],
join: [Function: join], --拼接路径url,不考虑连接处的/,方便
relative: [Function: relative],
toNamespacedPath: [Function: toNamespacedPath],
dirname: [Function: dirname], --获取目录
basename: [Function: basename], --获取包含后缀名的文件名
extname: [Function: extname], --获取后缀名
format: [Function: bound _format],
parse: [Function: parse],--把一个路径解析为对象
__dirname 【动态获取】当前文件模块所属目录的绝对路径
__filename 【动态获取】当前文件的绝对路径
- os模块
var os=require('os');
console.log(os);
console.log(os.cpus());
console.log(os.freemem());
//有以下方法可以获取/调用
arch: [Function: arch] { [Symbol(Symbol.toPrimitive)]: [Function] },
cpus: [Function: cpus],
endianness: [Function: endianness] { [Symbol(Symbol.toPrimitive)]: [Function] },
freemem: [Function: getFreeMem] { [Symbol(Symbol.toPrimitive)]: [Function] },
getPriority: [Function: getPriority],
homedir: [Function: hidden] { [Symbol(Symbol.toPrimitive)]: [Function] },
hostname: [Function: hidden] { [Symbol(Symbol.toPrimitive)]: [Function] },
loadavg: [Function: loadavg],
networkInterfaces: [Function: networkInterfaces],
platform: [Function: platform] { [Symbol(Symbol.toPrimitive)]: [Function] },
release: [Function: getOSRelease] { [Symbol(Symbol.toPrimitive)]: [Function] },
setPriority: [Function: setPriority],
tmpdir: [Function: tmpdir] { [Symbol(Symbol.toPrimitive)]: [Function] },
totalmem: [Function: getTotalMem] { [Symbol(Symbol.toPrimitive)]: [Function] },
type: [Function: getOSType] { [Symbol(Symbol.toPrimitive)]: [Function] },
version: [Function: getOSVersion] { [Symbol(Symbol.toPrimitive)]: [Function] },
userInfo: [Function: userInfo],
uptime: [Function: getUptime] { [Symbol(Symbol.toPrimitive)]: [Function] },
tmpDir: [Function: deprecated],
- http模块
var http=require('http');
http.createServer
.on("request",function(req,res){
//事件响应数据
//req.url --请求路径
//req.socket.remoteAddress --请求地址
//req.socket.remotePort --请求端口--默认端口号:0-65535
//res.end(); --res只能接受二进制或字符串数据,如果非上述情况,可通过JSON.stringify()转换封装
})
.listen(2400,function(){
//监听端口及启动状态
});
- 响应内容类型
指定数据内容类型
res.setHeader(‘Content-Type’,‘text/plain;charset=utf-8’);
var fs=require('fs');
var http=require('http');
http.createServer()
.on('request',function(req,res){
fs.readFile('012.js',function(err,data){
if(err){
// 指定数据内容类型为普通文本
res.setHeader('Content-Type','text/plain;charset=utf-8');
res.end('返错啦');
}else{
// 指定数据内容类型为html渲染
res.setHeader('Content-Type','text/html;charset=utf-8');
res.end(data);
}
})
})
.listen(2100,function(){
console.log('start');
});
- 客户端渲染与服务端渲染
服务端渲染:客户端只请求了一次,在服务端进行处理与渲染,响应的即是最终的结果,覆盖至客户端。
客户端渲染:第一次请求拿到的是页面,之后在解析过程中,ajax请求,则再次发起新的请求;第二次请求拿到的是动态数据,拿到ajax响应结果;再进行渲染。
Note: 客户端渲染不利于SEO搜索引擎优化;服务端渲染可以被爬虫获取,客户端异步渲染很难被爬虫到;真正的网站一般是两者结合
-
模板引擎art-template
安装:npm install art-template express-art-template
配置:
app.engine(‘html’,require(‘express-art-template’));/* 渲染文件后缀名/格式*/
app.set(‘views’,path.join(__dirname,’./views’));/默认目录设置/
使用:
1-{{变量}}
2–{{each 数组}} {{$value}} {{/each}}
3–模板引擎继承 {{extend ‘path’}}
4–引入子模板语法 {{include ‘path’}} -
模块作用域与访问
在Node中,没有全局作用域与函数作用域,只有模块作用域,无法访问到外部,也无法被外部访问。所以如果在多个文件中用到相同的核心模块,需要分别被定义。
require方法有2个作用:
1)加载核心模块并执行里面的代码
2)拿到被加载文件模块导出的接口对象
–导出多个对象:exports.a=123; exports.c=function(a,b){return a-b};
–直接导出单个对象:module.exports=function(a,b){ reurn a+b};
//实际上,在node中,每个模块内部都有一个module对象,在该对象中,有一个属性是exports,它也是对象;在程序的结尾,有一条 retuen module.exports语句;
//导出的接口对象实际上就是在给module.exports赋值;当导出多个对象时,为简化,对exports引用了module.exports的引用地址,即var exports=module.exoports;
var module={
exports:{ },
...
}
return module.exports;
- require加载模块规则
1)优先从缓存加载,避免重复加载,提高加载效率;
2)加载核心模块
核心模块文件已被编译到二进制文件中,只需按名字加载即可
3)加载第三方模块
当前文件所处目录中的node-modules/第三方模块名/package.json中的main属性,记录了art-template的入口模块;实际上最终加载的还是文件;
如果package.json文件不存在或者main指定的是错的,则node会自动找node_modules/art-template/目录下的index.js文件,即index.js会作为一个默认备选项;
如果以上所有条件都不成立,则会进入上一级目录的node_modules查找,以此循环;
如果均不成立,则返回cant find module xxx错误
4)加载自定义模块
以路径形式加载
模块查找机制:
优先从缓存加载
核心模块
路径形式的文件模块
第三方模块
- package.json与package-lock.json
初始化:npm init -yes
安装:npm install --save xxx
–save会保存依赖项dependencies至package.json中,用来保存第三方模块的依赖信息
如果node_modules丢失,只需要重新运行npm insall,就会自动把package.json中的依赖项下载回来;
在新版npm中,还会生成一个package-lock.json文件,保存了node_modules中所有包的信息(版本、下载地址),丢失后,npm install下载速度更快。
- 重定向
--原生
res.statusCode=302;//301-永久重定向,浏览器会记住 302-临时重定向,浏览器不记忆
res.setHeader('Location','/');
res.end();
--Express框架-服务端
res.redirect('/');
--异步提交--前端
window.location.href='/';
- 获取表单提交的信息
--原生(只能获取get)
//加载url模块
var url=require('url');
//在事件监听函数中通过url.parse方法将路径进行处理与解析
var parseObj=url.parse(req.url,true);
console.log(parseObj.pathname);
--Express框架
req.query //GET请求信息
req.body //POST请求信息,需要加载配置body-parser模块
- Express json响应方法
在Express中提供了一个响应方法,json,该方法会接收一个对象作为参数,它会自动帮你把对象转换为字符串再发送给浏览器(异步提交)
res.status(200).json({
err_code:0
message:'Success'
})
- Promise
https://es6.ruanyifeng.com/#docs/promise–ES6 Promise介绍
Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象。
所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。
Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。它们是两个函数,由 JavaScript 引擎提供,不用自己部署。
Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数。
then方法可以接受两个回调函数作为参数。第一个回调函数是Promise对象的状态变为resolved时调用,第二个回调函数是Promise对象的状态变为rejected时调用。其中,第二个函数是可选的,不一定要提供。这两个函数都接受Promise对象传出的值作为参数。
var promise = new Promise(function(resolve,reject){
if(1>2){
resolve();
}else{
reject();
}
});
promise.then(function(){
console.log('123');
},function(){
console.log('456');
});
- 中间件
中间件的本质就是一个请求处理方法,把用户从请求到响应的整改过程分发到多个中间件中去处理,这样的目的是提高代码的灵活性,使其动态可扩展。
中间件本身是一个方法,接收三个参数:
1)Request请求对象
2)Response响应对象
3)Next下一个中间件–需要调用next()才会进入/调用下一个中间件
分类:
一. 应用程序级别中间件
1)不关心请求路径和请求方法的中间件,如app.use()
2)关心请求路径的中间件,如app.use(’/ad’,function…)
二. 路由级别中间件
最常用的中间件,严格匹配请求方法和请求路径。如app.get() app.post() app.put() app.delete()
二. 错误处理中间件
app.use(function(err,req,res,next){});
三.内置中间件
四.第三方中间件
body-parser
session等
- 中间件是按顺序执行的,前一个不执行完成或交出控制权,是不会到下一个中间件的;
- next()不一定是调用紧紧相邻的,需要匹配条件才可以
- 如果没有能匹配的中间件,则Express会默认返回can not get /或 post/等错误。
- 当调用next时如果传递了参数err,如next(err),则直接往后定位到带有4个参数的应用程序级别中间件(错误处理中间件),可以利用该特点设置调用全局错误处理中间件。
// 配置挂载路由
var router=require('./router');
app.use(router); //把路由器挂载到app服务中
// 配置全局错误处理中间件,需要放在app.use(router)后面
app.use(function(err,req,res,next){
res.status(500).json({
err_code:500,
message:"Server Error"
})
});