function waitFive(name, callbackfn) {
var pus = 0
var currentDate = new Date()
while(pus < 5000) {
var now = new Date()
pus = now - currentDate
}
// 执行回调函数
callbackfn(name)
}
// 定义回调函数echo()
function echo(name) {
console.log(name)
}
// 调用waitFive方法
waitFive('回调函数被调用啦', echo)
console.log('略略略略')
var util = require('util')
var Person = require('./person')
// 定义Teacher类
function Teacher() {
Person.call(this)
}
// 将Teacher类继承Person类
util.inherits(Teacher, Person)
// 重写teach方法
Teacher.prototype.teach = function() {
console.log('我正在教学')
}
// 暴露Teacher类
module.exports = Teacher
为了加深下印象,我们再写一个Coder类继承Person类
var util = require("util")
var Person = require("./person")
// 定义个Coder类
function Coder() {
Person.call(this)
}
// 继承
util.inherits(Coder, Person)
// 重写code方法
Coder.prototype.code = function() {
console.log("我正在敲代码")
}
// 暴露Coder类
module.exports = Coder
下面我们进入重头戏,看看如何调用继承类,创个app.js文件
var Person = require('./person')
var Student = require('./student')
var Teacher = require('./teacher')
var Coder = require('./coder')
// 创建对象
var personObj = new Person()
var studentObj = new Student()
var teacherObj = new Teacher()
var coderObj = new Coder()
// 执行personObj对象的所有方法
console.log('---Person类---')
personObj.sleep()
personObj.eat()
console.log('----------')
// 执行studentObj对象的所有方法
console.log('---Student类---')
studentObj.sleep()
studentObj.eat()
studentObj.study()
console.log('----------')
// 执行teacherObj对象的所有方法
console.log('---Teacher类---')
teacherObj.sleep()
teacherObj.eat()
teacherObj.teach()
console.log('----------')
// 执行coderObj对象的所有方法
console.log('---Coder类---')
coderObj.sleep()
coderObj.eat()
coderObj.code()
console.log('----------')
var Single = require('./student')
var singleObjOne = new Single('2018-09-02')
var singleClassOne = singleObjOne.getInstance('2018-09-02')
singleClassOne.show()
var singleObjTwo = new Single('2018-09-01')
var singleClassTwo = singleObjTwo.getInstance('2018-09-01')
singleClassTwo.show()
var ConcreteDecoratorA = require('./concreteDecoratorA')
var ConcreteDecoratorB = require('./concreteDecoratorB')
var target = new ConcreteDecoratorA()
target.operation()
var targetone = new ConcreteDecoratorB()
targetone.operation()
targetone.addedBehavior()
var ProductA = require('./productA')
var ProductB = require('./productB')
exports.createProduct = function(type) {
switch(type) {
case 'ProductA' : return new ProductA
break
case 'ProductB' : return new ProductB
break
default : return false
}
}
最后创建一个测试文件
var ProductFactory = require('./productFactory')
var ProductA = ProductFactory.createProduct('ProductA')
ProductA.getProduct()
var ProductB = ProductFactory.createProduct('ProductB')
ProductB.getProduct()
工具
介绍一款很方便的在线编辑器——webIDE,点击进入官网。
前言
这是一本书的学习总结,书名为《Node.js开发实战详解》,作者为腾讯出身的黄丹华。由于这会是一篇很长的课程学习总结,为了优化大家的阅读体验,强烈建议安装Chrome浏览器的插件——GayHub。下载安装地址
第 1 章:Node.js基础知识
为什么使用Node
因为Node能处理高并发请求,而且由于Node.js是事件驱动,因此能够更好的节约服务器内存资源。同时,Node.js可以单独实现一个server,这也是Node一个非常大的优点,对于那些简单的server,通过Node实现比使用C++实现会简单得多。
最后,牢记Node解决了长连接、多请求引发的成本问题,因此在一些项目中,比如实时在线的游戏、实时聊天室、实时消息推送功能、实时监控系统等开发过程中,应该把握机会,应用Node来开发。
同步调用和异步调用
1、同步调用时一种阻塞式调用,一段代码调用另一段代码时,必须等待这段代码执行结束并返回结果后,代码才能继续执行下去。例如下面的代码
2、异步调用是一种非阻塞式调用,一段异步代码还未执行完,可以继续执行下一段代码逻辑,当其他同步代码执行完之后,通过回调返回继续执行相应的逻辑,而不耽误其他代码的执行。例如下面的代码
当然,关于异步还有另外一个例子,这个栗子也引出了异步调用和回调这两个东东的概念,下面请看代码
回调和异步调用
首先明确一点,回调并非是异步调用,回调是一种解决异步函数执行结果的处理方法。在异步调用里,如果我们希望将执行的结果返回并且处理时,可以通过回调的方法解决。为了能够更好的区分回调和异步回调的区别,下面看一个简单的栗子
以上代码是一个回调逻辑,但不是一个异步代码逻辑,因为其中并没有涉及Node的异步调用接口。从上面的代码结果可以看出回调和异步调用的区别,当waitFive()方法执行时,整个代码执行过程都会等待waitFive()方法的执行,而并非如异步调用那样:waitFive()方法未结束,还会继续执行console.log('略略略略')。这也说明了回调还是一种阻塞式调用。
获取异步函数的执行结果
异步函数往往不是直接返回执行结果,而是通过事件驱动的方式,将执行结果返回到回调函数中,之后在回调函数中处理相应的逻辑代码。
如何来理解以上的代码呢?请看下面一个代码案例
dns.resolve4()是一个异步函数,由此带来的问题就是console.log(address)输出的结果是undefined,因为你懂得,异步嘛,对不对。
既然异步函数会出现这个问题,那么我们就可以使用回调函数去获取参数,下面请看代码
第 2 章:模块和NPM
Node模块的概念
需要了解一点的是,Node会对原生模块和文件模块都进行缓存,因此在第二次require该模块的时候,不会有重复开销去加载模块,只需要从缓存中读取相应模块数据即可。
原生模块的调用
使用Node提供的API——require来加载相应的Node模块,require加载成功后会返回一个Node模块对象,该对象拥有该模块的所有属性和方法,如下代码
以上就是一个简单的调用原生模块的方法,Node中其他原生模块的调用方法都是一样的,主要是学会如何查看Node的API文档,以及如何应用其中的模块提供的方法和属性。
文件模块调用
文件模块的调用和原生模块的调用方式基本一致,但是需要注意的是,其两者的加载方式存在一定的区别,原生模块不需要指定模块路径,而文件模块加载时必须指定文件路径。比如我们在项目中创建一个test.js文件,代码如下
接着我们在同一个目录中创建diaoyong.js文件加载test.js这个文件模块,代码如下
以上代码也指明了,在文件模块中,只有exports和module.exports对象暴露给该外部的属性和方法,才能够通过返回的require对象进行调用,其他方法和属性是无法获取的。
Node原生模块实现web解析DNS
我们使用Node的原生模块和文件模块两个方法实现DNS解析工具,通过分析对比,来说明文件模块存在的必要性,以及其存在的必要性。
下面我们先看一下使用原生模块创建的DNS解析工具代码(先创建parse_dns_ex.js文件)
接着我们创建一个html文件,代码如下
然后我们在命令行输入命令:node parse_dns_ex.js,就能够在浏览器输入http://127.0.0.1:3000,看到HTML页面内容。
由于以上代码只是实现了一个表单提交的页面,对于DNS解析部分还没有做任何处理,因此我们需要对js文件做如下的处理
以上代码就能够实现当你输入www.qq.com的时候,显示它的IP。
Node文件模块实现web解析DNS
文件模块的好处在于将业务处理分离,每个模块处理相应的职责,避免业务混乱。接下来我们分析DNS解析系统需要划分哪些模块,以及这些模块之间的功能和作用分别是什么。下面就来看看各个模块的作用以及具体代码。
入口模块(index.js),创建http服务器处理客户端请求
路由处理模块(router.js),处理所有请求资源,分发到相应处理器。说白了就是负责url转发以及请求资源分配。
这里需要注意的是,router方法必须应用exports暴露给require返回的对象,如果不使用exports方法,相对于router.js文件模块来说就是私有方法,require router模块返回对象将无法调用。
DNS解析模块(parse_dns.js),DNS处理逻辑,根据获取的域名进行解析,返回相应的处理结果到页面,这部分代码和上面的原生模块的代码类似,主要是parseDns和getDns两个方法。
以上的js代码对应html代码为
首页展示模块(main_index.js),处理主页index.html页面的显示,使用fs模块进行读取index.html页面字符数据,然后返回到客户端。
整个过程结束后,运行index.js同样可以实现跟原生模块DNS解析的作用。
exports和module.exports
两者的作用都是将文件模块的方法和属性暴露给require返回的对象进行调用。但是二者存在本质的区别:exports的属性和方法都可以被module.exports替代,反过来则不行。它们之间还有以下的不同点
// 调用index.js文件模块 var Book = require('./index.js') console.log('调用Book:' + Book) console.log('调用Book中的name:' + Book.name) console.log('调用Book中的showName():' + Book.showName())
(2)实现person.js文件模块,其返回的是一个eat方法和say方法的对象
(3)实现person.js文件模块,其返回的是一个数组,数组内容为人名
(4)实现person.js文件模块,其返回的是一个对象,该对象中包含一个数组元素
使用Express
express是一个Node.js的web开源框架,该框架可以快速搭建web项目开发的框架。其主要集成了web的http服务器的创建、静态文件管理、服务器url请求处理、get和post请求分支、session处理等功能。下面是使用express的步骤
查看当前版本:express --version
使用jade模块
该模块的作用就是可以内嵌其他代码到html页面中,比如在html页面中内嵌php代码
下面我们在一个express项目中使用jade模块。首先创建一个jade.js文件,记得事先安装(npm install jade)好了jade模块
接着,创建一个test.jade模板
最后,在命令行终端运行:node jade.js。关于更多jade知识,可以点击这里进行学习。
习题检测
在安装好jade模块的express项目中,修改routes/index.js文件,传递一个名为info的json对象,json值为{'name':'jack','book':'Node.js'}。同时在views/index.jade页面使用div展示name,使用h2标签展示book
使用forever模块
服务器管理是系统上线后,必须要面对的问题。最好有一个软件可以提供整套的服务器运行解决方案:要求运行稳定,支持高并发,启动/停止命令简单,支持热部署,宕机重启,监控界面和日志,集群环境。接下来,就让我们使用forever模块来实现以上的要求。
使用步骤
更多关于forever模块的知识请点击这里,不过到了现在,该模块貌似被PM2给取代了,有兴趣的去看看吧。
使用socket.io模块
socket.io是一个基于Node.js的项目,其作用主要是将WebSocket协议应用到所有的浏览器。该模块主要应用于实时的长连接、多请求项目中,例如在线互联网游戏、实时聊天、实时股票查看、二维码扫描登录等。
由于书中给的案例并没有跑起来,因此只将其代码抄了下来,相关的解释说明等过后再说
以及客户端代码
使用request模块
request模块为Node.js开发者提供了一种简单访问HTTP请求的方法。在开始之前我们需要进行模块安装
npm install request
,不过在安装之前要记得先使用npm init
初始化一个package.json文件,否则模块是安装不上去的。下面我们来看重点内容,get和post请求。要牢记的是:get和post只是发送机制不同,并不是一个取一个发!
首先看看处理get请求,首先创建一个HTTP服务器发出一个请求(app_get.js)
然后通过request模块去请求该服务器数据,并将服务器返回结果打印出来(request_get.js)
应用request模块的get方法,发起一个HTTP请求,请求本地http://127.0.0.1:1337服务器数据,request.get()方法中的两个参数分别是请求url和回调函数。
接下来运行node app_get.js代码,启动服务器,可以到浏览器看看输出的内容;然后再打开一个命令行(记得之前启动服务器的命令行不要关闭),运行node request_get.js代码,可以看到从服务器中请求回来的数据。
下面我们再来看一看关于post请求的一些代码,和get方式类似,也是先创建一个HTTP服务器(app_post.js),该服务器接收客户端的post参数,并将该参数作为字符串响应到客户端
接着应用request模块发起HTTP的post请求,将数据传到HTTP服务器中,然后又取得服务器返回的数据(request_post.js)
接下来运行node app_post.js代码,启动服务器,可以到浏览器看看输出的内容;然后再打开一个命令行(记得之前启动服务器的命令行不要关闭),运行node request_post.js代码,可以看到从服务器中返回来处理过的数据,同时将HTTP请求方式也响应到客户端。
使用Formidable模块
formidable模块实现了上传和编码图片和视频。它支持GB级上传数据处理,支持多种客户端数据提交。有极高的测试覆盖率,非常适合在生产环境中使用。
在原生的Node.js模块中,提供了获取post数据的方法,但是没有直接获取上传文件的方法,因此需要利用formidable模块来处理文件上传逻辑。接下来我们看一下实例(记得先npm init,然后npm install formidable)
之后运行这个项目,上传一张图片即可看到效果。
开发一个自己的NPM模块
$ npm whoami fengxiong
1、创建一个新项目 2、初始化一个package.json文件 3、安装自己的模块:npm install --save "原先模块package.json文件中的name值"
然后在运行node test.js,那么就能得到相应的结果。
模块与类
模块是程序设计中,为完成某一功能所需的一段程序或者子程序;或者指能由编译程序,装配程序等处理的独立程序单位;或者指大型软件系统的一部分。
而在Node.js中可以理解为完成某一功能所需的程序或者子程序,同时也可以将Node.js的一个模块理解为一个“类”,但注意,其本身并非是类,而只是简单意义上的一个对象,该对象拥有多个方法和属性,Node.js模块也拥有私有成员和公有成员。
一般来说exports和module.exports的成员为公有成员,而非exports和module.exports的成员为私有成员。
Node.js中的继承
继承的方式主要是通过Node.js的util模块inherits的API来实现继承,将一个构造函数的原型方法继承到另一个构造函数中。
constructor构造函数的原型将被设置为使用superConstructor构造函数所创建的一个新对象。可以看看下面的栗子,其目的就是使用MyStream继承events.EventEmitter对象
上面的栗子可能稍微抽象些,下面我搞一个比较具体的栗子,比如:学生、老师、程序员继承人这个类,实现学生学习、老师教书、程序员写代码的功能。首先,我们创建一个Person基类作为人
下面我们再创建一个Student类继承Person类
这样就实现了student继承person类,同时新增类的自我方法study。下面我们再来看看实现一个Teacher类继承Person类
为了加深下印象,我们再写一个Coder类继承Person类
下面我们进入重头戏,看看如何调用继承类,创个app.js文件
之后在终端执行命令:node app.js,那么就可以看到继承的效果出现了。那么该如何改写父类定义好的方法呢?其实很简单,只要直接覆盖就行了,下面就来看看在Student类中重写父类的eat()方法
动态类对象和静态类对象
Node.js中可以应用module.exports实现一个动态类对象,那么Node.js中如何实现一个静态类对象呢?例如:假设有一个基类Person,其有继承类Student,但是我们希望使用静态类对象的方式调用Student中的方法和属性,而不希望new一个对象。可以结合exports以及继承方法来实现静态类。
首先,我们先使用动态类对象调用的方式实现一下代码
现在我们使用静态类对象的调用方式,调用Student中的对象,那么我们可以将student这个模块实现方式修改为如下代码(这一处书中代码有误,我修改过来了):
通过在类定义模块中new一个本身对象,并将该对象的方法全部通过exports暴露给外部接口,就无需在每次调用该类的地方new一个该对象了。因此在使用上就可以将student这个类看成一个静态类
这种方法实现很简单,也很容易理解,在很多时候非常有用。这样做的好处是可以避免代码的冗余,当student这个类被多个地方调用时,如果是动态调用的话,就必须每次都去new一个该对象,而如果使用类静态方法调用时,就可以直接通过require返回的对象进行调用。
当然,不是所有的类都可以这样去调用,如果每次在该类的内部new一个对象都需要初始化一些参数变量,那么就可以选择使用静态调用方法。
习题练习
实现一个基类animal,该基类包含方法say,该方法输出内容,接下来实现两个继承类duck和bird,其中duck是一个静态类模块,其有方法say,该方法输出ga..ga...ga..,而bird则是一个动态调用模块,其有方法输出ji...ji...ji...
单例模式
一般认为单例就是保证一个类只有一个实例,实现的方法一般是先判断实例存在与否,如果存在,就直接返回,如果不存在,则会创建该对象,并将该对象保存在静态变量中,当下次请求时,则可以直接返回该对象,这就确保了一个类只有一个实例对象。
下面请看一个例子,使用私有变量记录new的相应对象
注意,_instance变量是要放在单例方法之外,否则无法实现单例模式。原因是当调用单例方法时每次都会重新将其赋值为null,而放在单例函数之外时,调用单例函数不会影响到_instance变量的值。
接下来,我们再创建一个js文件来调用类对象
从输出结果可以看出来,第二次new单例对象的时候,没有创建新的Class类对象,而是返回了第一次创建的Class类对象。这样就应用Node.js实现了单例模式。
适配器模式
若将一个类的接口转换成客户希望的另外一个接口,Adapter(适配器)模式可以使原本由于接口不兼容而不能一起工作的那些类可以一起工作。下面我们直接看案例代码
从运行结果可以看到,其通过适配器调用了Adaptee中的specialRequest方法,这样就实现了Node.js中的适配器模式。
装饰模式
装饰模式就是动态的给一个对象添加一些额外的职责,就扩展功能而言,它比生成子类方式更为灵活。下面我们就先创一个Component父类
接着在创建一个子类ConcreteComponent,其作用就是展示父类装饰之前类中的属性和方法,重定义operation方法
然后再创建一个Decorator基类,用于装饰Component类
创建ConcreteDecoratorA装饰类,该类的目的是为Component类的operation方法提供一些额外的操作,比如添加一些额外的计算规则和输出一些额外的数据
创建ConcreteDecoratorB装饰类,该类的目的是为Component类的operation方法提供一些额外的操作,同时添加新的功能方法
最后我创建一个测试类
装饰类的应用场景是在不改变基类的情况下,为基类新增属性和方法。
工厂模式
定义一个用于创建对象的接口,让子类决定将哪一个类实例化,工厂模式就是使一个类的实例化延迟到其子类。下面我们编写一个基类Product
创建两个子类ProductA和ProductB,分别重写父类的getProduct方法
接着创建工厂对象productFactory,根据不同的参数获取不同的Product对象。这里需要注意的是,createProduct使用exports而不是使用module.exports,目的是传递一个ProductFactory对象,而非一个ProductFactory类
最后创建一个测试文件
从结果可以看出通过传递不同的字符串,获取了不同的对象ProductA和ProductB,在工厂模式中还包括工厂方法和抽象工厂两个模式。
第 3 章:Node.js的Web应用
简单的HTTP服务器
我们首先来看下面一个代码栗子,根据这个栗子进行分析
http.createServer()接收一个request事件函数,该事件函数有两个参数req和res。req主要是获取请求资源信息,包括请求的url、客户端参数、资源文件、header信息、HTTP版本、设置客户端编码等;res主要是响应客户端请求数据,包括HTTP的header处理、HTTP请求返回码、响应请求数据等。
http.createServer()调用返回的是一个server对象,server拥有listen和close方法,listen方法可以指定监听的IP和端口。
接下来我们整一个实例:创建一个HTTP服务器,获取并输出请求url、method和headers,同时根据请求资源做不同的输出。
然后node执行这个js文件(记住在当前项目中得存在一个html文件和logon.png文件)
路由处理
一般情况下,我们可以根据上一节内容那样来使用switch来实现路由,但是当请求资源非常复杂时,使用这种方式来判断处理就会显得很庞大,而且难以维护,下面介绍其他两种路由处理办法
特定规则请求参数:可以根据用户请求的url,依据特定的规则得到相应的执行函数,例如请求参数/index,根据特定规则转化为resIndex(res, req)方法。下面的代码就是将HTTP的请求路径/index,根据一定的规则得到其处理函数resIndex,当我们需要新增处理逻辑时,例如/img,则必须在服务器端新增处理函数resImg
利用自带参数来实现路由处理:url路径指定需要执行的模块,通过在HTTP的url中携带一个参数c,表示需要调用的方法名,从而实现简单的路由处理。例如/image?c=img表示获取index模块中img方法,同样/index?c=index表示获取index模块中的index方法
根据上述实现必须在本地路径创建image.js和index.js文件,其中两个模块中都含有init方法来初始化模块中的res和req变量。image.js中img方法处理图片返回,index.js中index方法处理index.html页面展示
Node中的GET
Node.js中HTTP客户端发送的GET请求参数数据都存储在request对象中的url属性中,例如:http://locallhost:1337/test?name=jack。其中ur的请求路径名为test,使用GET传输的name数据暴露在url上。
下面我们使用http模块创建一个服务器,该服务器接收任意的url请求资源,使用GET方法传递参数,服务器接收客户端请求url,输出每次请求的路径名和请求参数的json对象
在命令行运行该文件,分别输入:http://127.0.0.1:1337/ 、http://127.0.0.1:1337/index 、http://127.0.0.1:1337/index?id=4535 ,观察下输出的结果是什么。
Node中POST
相比较GET请求,POST请求一般比较复杂,Node为了使整个过程非阻塞,会将POST数据拆分成很多小的数据块,然后通过触发特定的事件,将这些小数据块有序传递给回调函数。这部分涉及到request对象中的addListener方法,该方法有两个事件参数data和end,data表示数据传输开始,end表示数据传输结束。下面我们来看一个实例
运行该js文件,然后打开地址:http://127.0.0.1:1337/ , 接着你会看到一个表单,往表单里面输入数据看看返回了什么,下面是index.html文件代码
Node中的POST和GET
上面介绍了HTTP中POST和GET参数的获取方式,现在我们将两个方法作为一个公用的模块,可以在很大程度上减少工作量,毕竟获取GET和POST参数的方法都不是一步完成的,都必须进行多步操作,接下来我们来实践开发一个HTTP参数获取模块,主要是利用其中的两个方法GET和POST来直接得到客户端传递的数据
在该模块起始部分,首先要获取该模块的一些必要的Node.js原生模块,分别是url和querystring,其次需要在代码中应用init方法来初始化该模块对象中的res和req对象,代码如下
在代码最后使用的是一个callback回调函数作为参数,来解决异步调用中返回结果的传递。这样就简单地实现了一个HTTP中如何获取GET和POST传递的数据模块。
下面这个是调用模块代码
运行该js文件,然后打开地址:http://127.0.0.1:1337/ , 接着你会看到一个表单,往表单里面输入数据看看返回了什么,下面是index.html文件代码
HTTP和HTTPS模块介绍
HTTP是一种详细规定了浏览器和万维网服务器之间互相通信的规则,通过因特网传送万维网文档的数据传送协议。
而HTTPS是以安全为目标的HTTP通道,简单的说他就是HTTP的安全版。
两者创建服务器的方式接口都是一致的,都是使用各自模块中的createServer方法,但是HTTPS中的createServer会附加一个参数opts,其中保存有key和cert的信息。
为什么需要静态资源管理
因为在对于前端种种类型的静态资源,服务器端无法为每个静态资源类型实现一个处理逻辑,因此在Web应用开发中我们需要自己设计一个静态资源的管理。请看以下代码
当你的index.html文件中新增了css外部静态资源时,那么该css将不会被处理
Node实现简单静态资源管理
接下来我们学习如何利用Node.js实现简单的静态资源管理。创建http.js,首先分析需要的Node.js模块:HTTP模块创建服务器、fs模块处理文件的读写、url模块处理url请求路径
在该项目中有一个index.html文件,以及以static文件夹以及文件夹下面的logo.png和style.css这两个静态资源文件
这里只针对两种类型的静态资源文件,对于其他的资源暂时不考虑,代码编写完后,运行http.js,打开浏览器输入http://localhost:1330/ ,那么你将看到静态资源被渲染出来了。
静态资源库设计
HTTP请求中大概有409中MMIE类型,在设计时将这409种MMIE类型作为一个json配置信息存储在mmie_type.json文件中,以便维护和管理,由于代码量多,具体的请看[这里]()。记得在写demo的时候需要添加上去
下面我们创建一个静态资源调用以及解析文件static_module.js
我们为了减轻硬盘IO的承受压力,因此对静态资源文件进行了缓存配置。其中的原理是:浏览器缓存中存有文件副本的时候,不能确定该文件是否有效时,会生成一个get请求,在该请求的header中包含If-Modified-Since参数。如果服务器端文件在这个时间后发生过更改,就发送整个文件给客户端,如果没有修改,则返回304状态码,并不发送整个文件给客户端。
如果确定该副本有效时,客户端不会发送GET请求。判断有效的主要方法是,服务端响应的时候带上expires的头,浏览器会判断expires头,直到指定的日期过期,才会发起新的请求
接着我们创建一个client.js文件,并且在node环境中运行
运行之后打开浏览器,查看当前请求资源的network信息,仔细观察下。其中index.html文件的内容是
文件处理
文件I/O是由标准的POSIX函数封装而成,需要使用require('fs')访问这个模块,所有的方法都提高了异步和同步两种方式
重命名文件
项目中txt格式的文件记得自己先创建一份,下面的几个文件处理也是同样的道理
修改文件权限和文件权限属组
获取文件元信息
验证文件是否存在
删除文件
图片和文件上传
本节涉及到Node.js中的API主要是HTTP、FileSystem、querystring和url等模块。HTTP模块创建服务器和HTTP的处理请求,FileSystem负责图片文件的处理,querystring处理字符串,url模块处理url解析。其中还涉及到了GET和POST请求处理模块和静态文件管理模块。
文件上传和图片上传前端页面原则上都是一致的,主要是通过POST文件数据,而Node.js服务器端则需要利用NPM中一个应用模块formidable来处理图片的上传。
我们先来看一下文件上传文件index.html
接着来看一下显示文件show_image.html
我们需要一个上传资源处理文件index.js
当然还有静态资源管理库文件static_module.js
以及POST和GET资源请求处理文件http_param.js
最后运行node index.js文件,查看效果。记得在那之前先执行npm init ==> npm install formidable --save
jade模板实现图片上传展示功能
由于Node版本更新迭代问题,这个章节的代码跑不起来,因此不做啥笔记了,先放着。
文件读写
由于Node版本更新迭代问题,这个章节的代码跑不起来,因此不做啥笔记了,又只能先放着。
Cookie和Session
Session和Cookie都是基于Web服务器的,不同的是Cookie存储在客户端,而Session存储在服务器端。
当用户在浏览网站的时候,Web服务器会在浏览器上存储一些当前用户的相关信息,而在本地Web客户端存储的就是Cookie数据。当下次用户再浏览同一个网站时,Web服务器就会先查看并读取本地的Cookie资料,如果有Cookie就会依据Cookie里的内容以及判断其过期时间来给用户特殊的数据返回。
Crypto模块加密
加密模块需要底层系统提供OpenSSL的支持,它提供了一种安全凭证的封装方式,可以用于HTTPS安全网络以及普通HTTP连接。该模块还提供了一套针对OpenSS的hash(哈希)、hmac(密钥哈希)、cipher(编码)、decipher(解码)、sign(签名)以及verify(验证)等方法的封装。
哈希
hash.digest()这个函数可以传入3个类型的参数hex(十六进制)、binary(二进制)或者base64输出加密后的字符,默认参数时binary。如果传递的参数非指定的这3个字符时,函数会自动使用binary返回加密字符串。
HMAC
HMAC是密钥相关的哈希运算消息认证码,HMAC运算利用哈希算法,以一个密钥和一个消息为输入,生成一个消息摘要作为输出。
Cipher和Decipher
如果希望对一个字符进行加密时,必须保证cipher对象和decipher对象加密的私钥和加密算法是相同的,才能正确的解密,解密和加密调用的所有函数都是类似的。