Node.js学习笔记(一)基础介绍
来源:互联网 发布:mac arp 嗅探工具dmg 编辑:程序博客网 时间:2024/05/01 09:54
什么是Node.js
官网介绍:
Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine. Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient.Node.js' package ecosystem, npm, is the largest ecosystem of open source libraries in the world.Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。 Node.js 使用了一个事件驱动、非阻塞式 I/O 的模型,使其轻量又高效。 Node.js 的包管理器 npm,是全球最大的开源库生态系统。
Node.js不是一个语言,也不是一个库,更不是一个框架。只是一个运行环境,也就是平台。在Node.js这个平台上,我们可以使用JavaScript 来编写程序,实现相应的功能。
使用Node.js 可以轻松地进行服务器端应用开发,PHP、Python、Ruby能做的事情,Node.js几乎都能做,而且可以做得更好。那么既然已经有了PHP等后台语言,为什么还需要Node.js?这里我们要知道一个理念——任何一个有点小规模的产品,都不会只使用一门技术或一种语言,结合多种语言来实现,然后在不同的场景、需求上,使用相应的语言和技术去实现。目的就是为了提高产品的性能。每一张语言都有自己的优缺点,我们要利用好它们的优点。
我们在考虑是否应该使用这门语言的时候,就是要搞清楚它的优缺点。时效性要求比较高的应用,Node.js是最佳的。
Node.js 初体验
官网下载安装好Node.js,接下来我们来初步感受一下。
Hello world
打开cmd窗口,输入node
命令,就可以进入Node.js的运行环境,在这里任何的JavaScript
代码都可以编写并执行,除了BOM 和 DOM 的内容。如果输入了 BOM 和 DOM 的一些内容,在 Node 平台就会出错。但是,node 平台也提供了一个全局对象——console
。
顺便说一句,像这种 cmd 的窗口,有一个专有名词 REPL
- R: read,读取,等待用户的输入
- E: eval,执行代码,输入代码完成之后,按回车键,可以执行代码
- P: print,打印,输出结果
- L: loop,循环,重复这个过程
执行js文件
上述的命令窗口模式操作node,平时很少会那样用。我们还是用编辑器编写js代码,然后会通过cmd窗口来执行这个文件。
过程也很简单,不需要进入node的REPL
环境,打开cmd
窗口,输入 “node + 文件名(完整路径)” 执行即可。
搭建服务器
下面我们用Node.js
来搭建HTTP服务器,
第一步:编写server.js文件如下:
<!--创建一个HTTP服务器-->// 载入http核心模块const http = require("http");// 创建一个server对象const server = http.createServer((req,res)=>{ // 通过res对象,输出一些内容 res.writeHead(200,{"Content-Type":"text/html;charset=utf-8"}); res.write("<h1>http服务器</h1>"); res.write("<p>使用Node.js创建一个http服务器</p>"); res.end();});// 开启server的监听server.listen(3000,()=>{ console.log("http server is listening in port 3000...");});
第二步:打开cmd窗口,执行server.js文件
第三步:在浏览器中,输入 localhost:3000
访问,即可看到结果页面。
模块机制
在Node.js中,所谓的模块,其实就是一个文件。一般而言,就是js文件/json文件。一个文件就是一个模块,模块是Node.js应用程序的基本组成部分。
模块分类
简单划分,可以将Node.js中的模块分成两大类:
- 系统模块(核心模块)
- 用户模块
其中,系统模块是Node.js自带的模块,比如http、fs、net、url、path等,可以直接使用。核心模块,Node.js中是内置好的。
用户模块不是Node.js本身的,又可以分为两种:
- 第三方模块,一些比较通用的,但是Node.js自身没有提供的,这一类数量很庞大
- 自定义模块,通常是在当前项目中,需要根据需求自己编写的js代码
加载模块
如何在Node.js中加载模块呢?
根据模块类型的不同,加载的方式略有不同。相同的是,都会使用 require
函数。格式:require(模块路径);
模块路径的写法,根据模块类型的不同,写法也不同:
- 核心模块和第三方模块的写法一样,只需要写上模块名即可。
- 自定义模块,需要使用相对路径来引入,必须使用
./
或者../
开头。
(1)核心模块的载入
核心模块是Node.js自带的,本身就具备的,直接载入就可以使用。
(2)第三方模块的载入
首先,需要保证有一个第三方模块,需要先安装第三方模块,使用npm 命令安装即可。
npm install 模块名。
本地安装的时候,需要先进入对应的目录,使用命令来安装。
虽然,加载模块的写法和核心模块一样,但是原理不太一样。如果是第三方模块,它最加载的时候,一定会在当前目录下,寻找 node_modules文件夹,在里面找对应的这模块,如果找到,就直接使用。如果没有找到,则会到父级目录中找node_modules文件夹,找是否有该模块,重复这个过程,直到根目录。如果到根目录,也没有找到,就会报错。
(3)加载自定义模块
先创建一个模块,其实就是一个js文件:mymodule.js
然后,使用require引入,const myModule = require('./mymodule.js');
如果没有使用相对路径,会报错。
还有几个细节需要注意一下:
- 模块就是文件,一般就是js文件,js文件是有后缀的,后缀是可以省略的,核心模块和第三方模块必须省略,自定义模块比较随意,两种都行。
- 如果没有写后缀,
require
方法在加载的时候,当文件不带后缀,Node.js会依照 目录 ->.js-> .json-> .node 的顺序进行查找,如果所有模块路径都找不到该文件,则抛出异常。
自定义模块的实现
默认情况下,任何一个模块,被载入时,得到的是一个空对象,就是 module.exports
;我们可以直接在js文件中使用module.exports
。
在Node.js中,还有一个对象exports
,它实际上是module.exports
的一个引用,相当于exports = module.exports
。
如果使用的是module.exports
,那么直接赋值即可,如果使用的是exports
,不能直接赋值,原因很简单嘛,又涉及到了对象数值的传递了。所以小结一下:
任何一个模块(js文件)被 require
时,返回的是 module.exports
对象,默认为空。Node.js为了方便,提供了一个exports
对象,指向module.exports
,相当于执行了exports=module.exports
。如果需要提供对外接口,需要给module.exports
赋值为一个新的对象,或者使用exports.属性名=值
的形式。
为了保险起见,我们可以写成:exports = module.exports = {}
。
Node.js进行Web开发的核心
Server 对象
作用:用于创建服务器对象,提供HTTP服务,在Node.js中,Server对象充当了HTTP服务器的角色。它提供了一个监听端口的底层套接字和接收请求,然后发送响应给客户端链接的处理程序。
创建对象:http.createServer();
核心方法:listen;启动监听,启动 http 服务,提供给用户来访问,有一个关键参数port,指定监听的端口
重要事件:request:接收请求时触发,传递两个参数,IncommingMessage 对象和 ServerResponse 对象;
listening:调用listen 时触发,同理也可以作为listen的回调函数来进行绑定。
实际上,用户输入url打开网页就是一个请求事件,如果我们需要响应用户的请求,那么必须先注册该事件。需要对server绑定一个request事件,在Node.js中,绑定事件使用 on 来完成。为了简化代码的书写,Node.js将注册request事件,使用回调函数的方式来实现:
const server = http.createServer();server.on('request',(req,res)=>{...});简化成const server = http.createServer((req,res)=>{...});
ServerResponse 对象
在刚才的 createServer 的回调函数中,使用了 res 对象,这个对象实际上就是 ServerResponse 对象,服务器端的响应对象。
作用:用来写http响应,包括响应状态行、响应头信息和响应正文。
创建:是自动创建的,作为回调函数的参数,自动创建好的一个对象。在createServer方法中的回调函数中,作为第二个参数来出现的。
重要属性和方法:
- writeHead用于写 响应状态行和响应头。只能调用一次
- write负责写 响应正文。可以调用多次
- end,响应完毕,只能调用一次,必须要调用。
- setHeader,也可以通过这个方法设置头信息
- getHeader,用来获取头信息的。
IncommingMessage 对象
作用:要理解其作用,需要看看HTTP请求和响应的过程:浏览器到服务器端的请求过程,作为服务器端需要获取来自客户端的信息;服务器端到浏览器端的响应过程,作为浏览器端也需要获取来自服务器的一些信息。需要有一个对象,来表示这个信息,这个对象就是 incomingMessage对象。简单来说,它的作用就是获取对方(浏览器端或者服务器端)的一些信息。
如何创建:不需要手动创建,也是作为回调函数的参数出现的。站在服务器端的角度来看,这个incomingMessage 就是 createSever回调函数中的req参数。
重要的属性和方法:
- httpVersion:请求/响应的HTTP版本
- headers:请求/响应头信息
- rawHeaders:原始请求/响应头信息
- method:请求方式,仅对Server获得到的请求(request)有效
- url:请求的url字符串,仅对Server获得到的请求(request)有效
- statusCode:响应状态码,仅对从ClientRequest获得响应(response)有效
重要事件:
- data:数据传递时触发
- end:没有更多数据提供时触发
由Readable Stream 提供了一下接口,然后 IncomingMessage实现了这些接口
ClientRequest 对象
什么是ClientRequest对象呢?就是客户端请求对象,表示一个已经产生且正在进项中的HTTP请求。
使用Node创建Web客户端,需要引入http模块。
如何创建:有两种方法,都是http对象的方法
- request
get
const cr = http.request();const cr = http.get();
核心方法:
- write:把一个正文写入请求;
- end:完成请求,也可以写入数据,end方法,完成请求的动作,针对request方法创建的对象而言。
对于get请求,请求正文是空的,不用写,此时,不需要write方法;对于post请求,请求正文是需要写的,此时,需要写write方法。
重要事件:response,需要注册一个响应事件,当发出请求后,需要监听来自服务器端的响应。
在响应时的监听器中,有一个重要的对象 IncommingMessage 对象,这个对象有两个重要的事件。
- data,数据传递时触发,
- end,没有更多数据提供时触发
使用这两个事件就可以获取来自服务器端的响应内容。代码如下:
const http = require('http');<!--创建一个ClientRequest对象-->const cr = http.request({host:'www.baidu.com'});//注册response事件cr.on('response',(res)=>{ let str = ''; //注册data事件 res.on('data',(chunk)=>{ str += chunk; }); res.on('end',()=>{ console.log(str); });});//发出请求cr.end();
针对上述过程,我们还可以使用get方法来简化,其中,get方法,会自动发出请求,不需要调用end方法。
const http = require('http');http.get('http://www.baidu.com',(res)=>{ let str = ""; res.on('data',(chunk)=>{ str += chunk; }); res.on('end',()=>{ console.log(str); });});
利用这个可以搞一下爬虫,爬一下网络资源。
简单应用
URL路由
URL:Uniform Resource Locator。统一资源定位器。还有一个就是URI(统一资源标识符),其中的I是指identifier。URL是基于URI的。在互联网中,任何一个资源(html、css、js、img、动画、视频、音频、word)需要保证它的唯一性。可以给每一个资源指定一个唯一的URL。简单来说,URL就是我们常说的网址。
在web当中,用户输入不同的URL,服务器就接收到这个信息,需要处理这个信息,根据不同的请求,返回相应的内容。这个过程就是URL路由。我们可以通过req对象(IncomingMessage对象)中的url属性,来获取相关的信息,并进行处理。
Node.js提供了一个url模块,可以解析url,得到更为详细的信息。url.parse(url)
得到一个对象,里边包含整个url中的各种信息。
代码片段:
浏览器输入 localhost:3000/user?username=admin&pwd=123路由处理 let realUrl = "http://"+ req.headers.host + req.url; let urlObj = url.parse(realUrl);//得到查询字符串query : 'username=admin&pwd=123'
解析查询字符串
打开一个网页,很多情况下路径名不发生变化,改变查询字符串,就会显示不同内容;附加的一些信息,需要根据这些信息,显示不同的内容给用户。
格式:?键1=值1&键2=值2&键n=值n
使用url.parse方法解析url之后,可以拿到查询字符串
Node.js提供了querystring 模块,其中有 parse 方法,可以将字符串解析成对象;这样就可以直接通过属性来获取相对应的值。
代码片段:
浏览器输入 localhost:3000/user?username=admin&pwd=123const querystring = require('querystring');let realUrl = "http://"+ req.headers.host + req.url;let urlObj = url.parse(realUrl);//得到查询字符串query : 'username=admin&pwd=123'let qObj = querystring.parse(urlObj.query);//得到{username: 'admin', pwd: '123'}
如何载入静态页面
在Node.js中,提供一个 web 服务器,有三种方式:
- 手动实现:结合 fs 文件操作;
- 第三方库实现:http-server
- 框架实现:express
看一下手动实现:
第一步:准备一个静态的HTML页面index.html;
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Document</title> <link rel="stylesheet" href="index.css"></head><body> <h1>载入静态页面</h1> <p>可以结合fs操作,实现载入静态页面</p> <img src="xx.jpg" alt=""></body></html>
第二步:编码,创建一个 web 服务器,当用户输入url,需要显示静态页面;在这个过程中,由于图片和CSS都是独立的文件,对于它们,其实浏览器分别发送了单独的请求,而不是像之前那样直接去读取。所以,我们要在服务器端对这些静态文件进行处理,并通过res返回给浏览器端。
const http = require('http');const fs = require('fs');const url = require('url');http.createServer( (req,res) => { let realUrl = "http://" + req.headers.host + req.url; let urlObj = url.parse(realUrl);switch(urlObj.pathname) { case "/" : //首页 case "/index": //使用fs读取html文件,然后输出 fs.readFile('index.html','utf8',(err,data) => { if (err) throw err; //读取成功,写入响应中 res.writeHead(200,{"content-type":"text/html;charset=utf-8"}); res.end(data); }); break; default: //res.writeHead(200,{"content-type":"text/html;charset=utf-8"}); //res.end('页面走丢了'); //将所有其他的资源,在这里做处理 if (fs.existsSync(__dirname + urlObj.pathname)) { fs.readFile(__dirname + urlObj.pathname,(err,data) => { if (err) throw err; res.statusCode = 200; res.end(data); }); } }}).listen(3000,() => { console.log('listening in port 3000...');});
这里使用了一个魔术常量 __dirname
,表示当前代码执行的路径。
POST请求及响应
典型的动态交互,表单处理。通常就是post请求。看一下Node.js是如何实现post请求和回应的。
第一步,准备一个表单,注意:要写获取到表单数据,必须要为input添加name属性,否则提交到服务器中的数据无法确定哪个是哪个,如下:
<form action="/signin" method="post" > <ul> <li> <label for="">用户名:</label> <input type="text" name="username"> </li> <li> <label for="">密码:</label> <input type="password" name="password"> </li> <li> <label for=""></label> <input type="submit" value="登录"> </li> </ul></form>
第二步,创建一个web server,载入这个表单;此时,会需要使用 IncommingMessage 对象的两个事件 data 和 end,
switch (urlObj.pathname) { case '/login' : //登录页面 fs.readFile('login.html','utf8',(err,data)=>{ if (err) throw err; res.writeHead(200, {"content-type" : "text/html"}); res.end(data); }); break; case '/signin': //console.log('提交到这儿了'); //需要接受用户填写的信息,利用IncomingMesaage对象的data和end事件 let str = ""; req.on('data', (chunk)=> { str += chunk; } ); req.on('end',()=>{ //表示提交完毕,str就是提交的数据了 console.log(str); //username=admin&password=1234 //利用querystring对象的parse方法进行解析 let userObj = querystring.parse(str); res.writeHead(200,{"content-type":"text/html;charset=utf-8"}); res.write(`<p>你输入的用户名是 ${userObj.username}</p>`); res.write(`<p>你输入的密码是 ${userObj.password}</p>`); res.end(); }); break; default: break; }}).listen(3005, () => { console.log('listening in port 3005');});
需要注册两个事件,data和end。数据提交的时候,并不是一次提交完毕,而是一块一块的提交。每提交一块,就触发一次,需要不停的累加。直到end触发了,说明提交完成了。
小结
以上是Node.js的基础介绍,接下来的学习更多的是不同模块的应用,和框架的学习了(express)。
- Node.js学习笔记(一)基础介绍
- Node.js学习笔记(一)基础介绍
- Node.js学习笔记(一)基础介绍
- Node.js学习笔记(一)基础介绍
- Node.js学习笔记(一)基础介绍
- Node.js学习笔记(一)基础介绍
- Node.js学习笔记(一)—— Node基础
- node js 学习笔记(一) 常用模块介绍
- 【慕课网】NODE.JS基础(一)学习笔记
- Node.js学习笔记(一)-认识Node.js
- 学习笔记:Node.js(一)
- Node.js 学习笔记 (一)
- node.js学习笔记(一)
- node.js学习笔记(一)
- node.js学习笔记(一)
- node.js学习笔记(一)
- Node.js学习笔记(一)安装
- Node.js基础(一)
- 【网络流】HDU 1532 Drainage Ditches(最大流Ford-Fulkersson)+HDU 3549 Flow Problem(最大流Dinic算法)
- keepalived+nginx双机热备+负载均衡
- 1091. Acute Stroke
- jfinal的初识及感悟
- virtualbox 在WIN10系统下与ubuntu实现文件夹共享
- Node.js学习笔记(一)基础介绍
- ajax与springMVC交互
- 在CentOS环境下安装mysql数据库
- RAC FAILover详解
- 算法训练 最短路 蓝桥杯
- 线上飙升800%,load达到12的解决过程
- Tomcat远程调试的方法(Tomcat与JDPA)
- 残缺棋盘问题
- 多表查询