首先认识一下node.js
Node.js 是一个让 JavaScript 运行在服务端的开发平台,它让 JavaScript 成为与PHP、Python、Perl、Ruby 等服务端语言平起平坐的脚本语言。发布于2009年5月,由Ryan Dahl开发,实质是对Chrome V8引擎进行了封装。
Node.js对一些特殊用例进行优化,提供替代的API,使得V8在非浏览器环境下运行得更好。V8引擎执行Javascript的速度非常快,性能非常好。Node.js是一个基于Chrome JavaScript运行时建立的平台, 用于方便地搭建响应速度快、易于扩展的网络应用。Node.js 使用事件驱动, 非阻塞I/O 模型而得以轻量和高效,非常适合在分布式设备上运行数据密集型的实时应用。
以上是百度的定义,node.js就是让javascript运行在服务端,所以使用的语言就是javascript,它有一个特性,就是上文提到的非阻塞I/O模型,可以简单的理解为异步执行,也就是说node.js不会从前到后按顺序依次执行代码指令,而有可能前面的指令还没执行完毕,后面的代码就已经开始执行了,这个特性往往会让新手在初学阶段摸不到头脑,不过没关系,使用多了,自然就对异步的概念清楚了。
这篇博客就是使用node.js来部署简单的web后端,实现前后端的通信,接收前端的get、post请求,向前端发送数据、页面等,node.js的安装与环境配置,网上很多资源,就不再累述,下面就进入正题。
运行.js程序
首先创建一个.js文件,最简单的方法就是创建一个文本文件,将后缀改为.js,也可以用编译器创建,创建好了,如下:
用编译器或者记事本等打开,写入一行命令,如下:
然后打开cmd命令窗口,cd到.js文件所在的目录,接下来,如果环境配置好了,可以使用node server.js或者省略后缀node server来运行.js程序,如下:
看到已经成功打印出hello了。
架设http服务器
前面是铺垫,从这里开始我们就要真正的假设一个服务器了。
我们一般访问一个网页,会从地址栏输入一个网址
https代表Web浏览器和网站服务器之间传递信息遵从https协议,以前都是用http协议传输,但现在已经逐渐都在使用https了,因为https比http更加安全。
www.baidu.com就是百度的域名,没有注册域名之前,我们可以使用"ip地址:端口号"的形式来访问,比如https://localhost:8888,localhost即访问本机,也可以是其他的ip地址。
http模块
架设http服务器,http模块是必不可少的。
我们分3步走:
这样我们就建好了一个最简单的http服务器,我们运行server.js程序,然后在浏览器地址栏里输入http://localhost:8888,访问,
可以看到后端输出new message说明后端接收到了前端的请求。我们后端监听的是8888端口,并且前端访问的也是8888端口,所以当前端向后端发送请求时,后端监听到8888端口有请求,于是就会调用http服务,打印出new messge,这就是程序执行的过程。
http服务里面接收两个参数req和res,req是request的缩写,res是response的缩写,一个代表请求,一个代表回应,前端向后端发送的数据一般在req里,而后端向前端返回数据时,一般用res向前端返回,具体用法,往下看。
架设路由
路由这个概念是网络中很重要的一个概念,但具体含义我也解释不太清楚,在这里可以简单理解为后端不同的分支对应前端不同的请求吧,看一下事例,就能够非常清晰的解释了。
req有许多的属性,感兴趣的可以打印一下req,可以看到有非常多的属性,我们这里用到一个比较重要的属性url,url是统一资源定位符,对可以从互联网上得到的资源的位置和访问方法的一种简洁的表示,是互联网上标准资源的地址。
刚刚我们请求的是http://localhost:8888,接下来我们请求比如http://localhost:8888/index
然后打印req.url,输出如下:
可以看到对于不同的请求地址,req.url也是不同的,这意味着我们可以架设不同的分支,来处理不同的请求。事例如下:
再试试请求不同的地址:
很明显不同的请求,后端进入了不同的分支,并向前端返回不同的消息,这就是架设路由。
我们这里用到了一个新函数,res.write(),顾名思义,就是写入数据,而我们的对象是res,也就是前端页面,所以我们向前端页面传送了一串字符数据,注意这里write()后面一定要跟上end()来结束传输,不然前端是收不到数据的,会一直处于等待后端响应的状态。
解析GET请求,获取参数
在实际使用中,前端常常会向后端传送一些数据,我们需要知道,只要是在地址栏里输入地址来访问页面,都是发送一个GET请求,此时GET请求的参数可以在url中获取:
地址?后面所接的就是GET请求传送的数据,下面我们讲如何从后端获取这里的数据。
为了解析url,我们需要引入url模块。
请求图中url,解析后,返回一个urlobject对象,它的属性如下:
可以看到参数在query属性里,路由则在pathname里。但是query是以字符串的方式储存的参数的,使用时不方便,我们可以在url.parse()里添加第二个参数true,这样解析时就会自动把参数转换为对象了。
fs模块
fs是file system的简称,用于读写文件。
下面介绍几个重要的函数
var fs = require('fs')
fs.exist(path, function (bol) {//功能是判断一个文件是否存在
//第一个参数是需要判断的文件的路径,为一个字符串
//第二个参数是一个回调函数,回调函数的参数为一个布尔类型,如果为true则文件存在,否则不存在
})
fs.realpath(path, function (err, realpath) {//功能是把相对路径转换为绝对路径
//第一个参数是相对路径,
//回调函数的第一个参数是错误信息,若成功,则第二个参数保存转换成功的绝对路径
})
fs.rename(path, new_name, function (err) {//功能是重命名一个文件
//第一个参数是需要修改的源文件路径
//第二个参数是重新命名的名字
//回调函数的参数是若修改失败的错误信息
})
fs.readFile(path, coded_format, function (err,data) {//功能是读一个文件
//第一个参数路径是读取的文件路径
//第二个参数是读取时的编码格式,如'utf-8'
//回调函数的参数,err是若错误的错误信息,data是若成功,读取的数据
})
fs.writeFile(path, content,operation, function (err) {
//第一个参数是写入的文件路径
//第二个参数是写入的内容
//第三个参数是写入控制操作,如覆盖写入、追加写入、指定编码格式等
//回调函数的参数err指示错误信息
})
对于较大的文件,应使用管道流的方式读写,管道流与普通的读写方式的区别是,普通的读写方式,是整读整写,一次性操作;而管道流是分块读写,每次传输64k大小的数据。管道流的优势是,如果传输过程中出现错误,那么之前已经传输的内容不会丢失,下次只要接着传输就可以了,而普通读写,如果出现错误,则这次读写的失败了。不过因为管道流的分块读写方式,我们需要把收到的数据拼接起来,才能获得完整数据。
var fs = require('fs')
var stream = fs.createReadStream(path)//创建一个读取流,参数是读取的文件的路径
var data = null
stream.on('data', function (chunk) {
//为读取流绑定读取事件,每一次读取都会触发,chunk的意思是片、块,就是一次读取的数据块
data += chunk//拼接数据
})
console.log(data)//完整数据
stream.on('end', function () {
//读取结束时触发
})
//数据是buffer类型时,可以用toString()方法转换成字符串
var fs = require('fs')
var stream = fs.createWriteStream(path)//创建一个写入流,参数是写入的文件的路径
stream.write(content)//通过管道流的方式写入,参数是写入内容
readStream.pipe(writeStream)//也可以用这种方式把读取流的数据写入写入流,这种方式与上面一种的区别是,它会等待每次数据写入完成后,才会进行下一次读取,内存利用率高。而上一种方法,读取速度快于写入速度,则等待写入的数据会滞留在内存中,占用内存。
解析POST请求
post和get请求是前后端交互最重要的请求,post与get请求的区别是,get请求的参数是拼接在url后面的,而post请求的参数却是在头部,post请求是通过发送数据包的方式把数据在前端与后端之间传输,下面我们就介绍如何把参数从post请求解析出来。
首先准备一个html页面,做演示用:
请求http://localhost:8888/index.html,后端会向前端发送这个页面。后端代码:
在账号栏和密码栏填入123,点击提交,后端显示如下:
然后把method改为POST,再请求,后端显示如下:
参数不能通过与get请求同样的方法获取,说明参数放在别的地方。
将后端代码修改如下,用管道流的方式把数据从req中提取出来:
var http = require('http')
var url = require('url')
var fs = require('fs')
var server = http.createServer(function (req, res) {
var urlObj = url.parse(req.url,true);
if(urlObj.pathname=="/index.html"){
var rs = fs.createReadStream("./index.html");
var index = null;
rs.on('data',function(chunk){
index+=chunk
})
rs.pipe(res)
}
else if(urlObj.pathname=="/login"){
var data = '';
req.on('data',function(chunk){
data+=chunk
});
req.on('end',function(){
console.log(data)
})
}
})
server.listen(8888, function () {
console.log('start server')
})
后端输出如下:
我们已经成功获取了POST请求的数据,但是它不是我们想要的格式,我们可以引用一个第三方库'querystring' :
var qs = require('querystring')
...
req.on('end',function(){
var queryObj = qs.parse(data)
console.log(queryObj)
})
...
后台输出如下:
当我们使用express模块时,还可以使用body-parser中间件来解析数据,对于body-parser的使用,这篇博客写的很详细
https://blog.csdn.net/yanyang1116/article/details/54847560